✨(backend) annotate number of accesses on documents
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.
This commit is contained in:
committed by
Anthony LC
parent
89d9075850
commit
774c2ce248
@@ -28,6 +28,7 @@ and this project adheres to
|
|||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
|
- ✨(backend) annotate number of accesses on documents in list view #411
|
||||||
- ✨(backend) allow users to mark/unmark documents as favorite #411
|
- ✨(backend) allow users to mark/unmark documents as favorite #411
|
||||||
- 🌐(backend) add German translation #259
|
- 🌐(backend) add German translation #259
|
||||||
- 🌐(frontend) add German translation #255
|
- 🌐(frontend) add German translation #255
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ class ListDocumentSerializer(BaseResourceSerializer):
|
|||||||
"""Serialize documents with limited fields for display in lists."""
|
"""Serialize documents with limited fields for display in lists."""
|
||||||
|
|
||||||
is_favorite = serializers.BooleanField(read_only=True)
|
is_favorite = serializers.BooleanField(read_only=True)
|
||||||
|
nb_accesses = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Document
|
model = models.Document
|
||||||
@@ -152,6 +153,7 @@ class ListDocumentSerializer(BaseResourceSerializer):
|
|||||||
"is_favorite",
|
"is_favorite",
|
||||||
"link_role",
|
"link_role",
|
||||||
"link_reach",
|
"link_reach",
|
||||||
|
"nb_accesses",
|
||||||
"title",
|
"title",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
]
|
]
|
||||||
@@ -162,6 +164,7 @@ class ListDocumentSerializer(BaseResourceSerializer):
|
|||||||
"is_favorite",
|
"is_favorite",
|
||||||
"link_role",
|
"link_role",
|
||||||
"link_reach",
|
"link_reach",
|
||||||
|
"nb_accesses",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -181,6 +184,7 @@ class DocumentSerializer(ListDocumentSerializer):
|
|||||||
"is_favorite",
|
"is_favorite",
|
||||||
"link_role",
|
"link_role",
|
||||||
"link_reach",
|
"link_reach",
|
||||||
|
"nb_accesses",
|
||||||
"title",
|
"title",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
]
|
]
|
||||||
@@ -191,6 +195,7 @@ class DocumentSerializer(ListDocumentSerializer):
|
|||||||
"is_avorite",
|
"is_avorite",
|
||||||
"link_role",
|
"link_role",
|
||||||
"link_reach",
|
"link_reach",
|
||||||
|
"nb_accesses",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
"""API endpoints"""
|
"""API endpoints"""
|
||||||
|
# pylint: disable=too-many-lines
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
@@ -10,6 +11,7 @@ from django.contrib.postgres.search import TrigramSimilarity
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
|
Count,
|
||||||
Exists,
|
Exists,
|
||||||
Min,
|
Min,
|
||||||
OuterRef,
|
OuterRef,
|
||||||
@@ -334,6 +336,9 @@ class DocumentViewSet(
|
|||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
user = self.request.user
|
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 not user.is_authenticated:
|
||||||
# If the user is not authenticated, annotate `is_favorite` as False
|
# If the user is not authenticated, annotate `is_favorite` as False
|
||||||
return queryset.annotate(is_favorite=Value(False))
|
return queryset.annotate(is_favorite=Value(False))
|
||||||
@@ -360,6 +365,7 @@ class DocumentViewSet(
|
|||||||
"""Restrict resources returned by the list endpoint"""
|
"""Restrict resources returned by the list endpoint"""
|
||||||
queryset = self.filter_queryset(self.get_queryset())
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
|
|
||||||
if user.is_authenticated:
|
if user.is_authenticated:
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
Q(accesses__user=user)
|
Q(accesses__user=user)
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ def test_api_documents_list_format():
|
|||||||
client = APIClient()
|
client = APIClient()
|
||||||
client.force_login(user)
|
client.force_login(user)
|
||||||
|
|
||||||
|
other_users = factories.UserFactory.create_batch(3)
|
||||||
document = factories.DocumentFactory(
|
document = factories.DocumentFactory(
|
||||||
users=[user, *factories.UserFactory.create_batch(2)],
|
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/")
|
response = client.get("/api/v1.0/documents/")
|
||||||
@@ -63,6 +65,7 @@ def test_api_documents_list_format():
|
|||||||
"is_favorite": True,
|
"is_favorite": True,
|
||||||
"link_reach": document.link_reach,
|
"link_reach": document.link_reach,
|
||||||
"link_role": document.link_role,
|
"link_role": document.link_role,
|
||||||
|
"nb_accesses": 3,
|
||||||
"title": document.title,
|
"title": document.title,
|
||||||
"updated_at": document.updated_at.isoformat().replace("+00:00", "Z"),
|
"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}
|
expected_ids = {str(document.id) for document in documents}
|
||||||
|
|
||||||
with django_assert_num_queries(3):
|
with django_assert_num_queries(3):
|
||||||
response = client.get(
|
response = client.get("/api/v1.0/documents/")
|
||||||
"/api/v1.0/documents/",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
results = response.json()["results"]
|
results = response.json()["results"]
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ def test_api_documents_retrieve_anonymous_public():
|
|||||||
"versions_list": False,
|
"versions_list": False,
|
||||||
"versions_retrieve": False,
|
"versions_retrieve": False,
|
||||||
},
|
},
|
||||||
|
"nb_accesses": 0,
|
||||||
"content": document.content,
|
"content": document.content,
|
||||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||||
"is_favorite": False,
|
"is_favorite": False,
|
||||||
@@ -102,6 +103,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated(
|
|||||||
"is_favorite": False,
|
"is_favorite": False,
|
||||||
"link_reach": reach,
|
"link_reach": reach,
|
||||||
"link_role": document.link_role,
|
"link_role": document.link_role,
|
||||||
|
"nb_accesses": 0,
|
||||||
"title": document.title,
|
"title": document.title,
|
||||||
"updated_at": document.updated_at.isoformat().replace("+00:00", "Z"),
|
"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,
|
"is_favorite": False,
|
||||||
"link_reach": document.link_reach,
|
"link_reach": document.link_reach,
|
||||||
"link_role": document.link_role,
|
"link_role": document.link_role,
|
||||||
|
"nb_accesses": 2,
|
||||||
"title": document.title,
|
"title": document.title,
|
||||||
"updated_at": document.updated_at.isoformat().replace("+00:00", "Z"),
|
"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() == {
|
assert response.json() == {
|
||||||
"id": str(document.id),
|
"id": str(document.id),
|
||||||
"abilities": document.get_abilities(user),
|
"abilities": document.get_abilities(user),
|
||||||
|
"nb_accesses": 5,
|
||||||
"content": document.content,
|
"content": document.content,
|
||||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||||
"is_favorite": False,
|
"is_favorite": False,
|
||||||
@@ -326,6 +330,7 @@ def test_api_documents_retrieve_authenticated_related_team_administrators(
|
|||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": str(document.id),
|
"id": str(document.id),
|
||||||
"abilities": document.get_abilities(user),
|
"abilities": document.get_abilities(user),
|
||||||
|
"nb_accesses": 5,
|
||||||
"content": document.content,
|
"content": document.content,
|
||||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||||
"is_favorite": False,
|
"is_favorite": False,
|
||||||
@@ -381,6 +386,7 @@ def test_api_documents_retrieve_authenticated_related_team_owners(
|
|||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": str(document.id),
|
"id": str(document.id),
|
||||||
"abilities": document.get_abilities(user),
|
"abilities": document.get_abilities(user),
|
||||||
|
"nb_accesses": 5,
|
||||||
"content": document.content,
|
"content": document.content,
|
||||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||||
"is_favorite": False,
|
"is_favorite": False,
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ def test_api_documents_update_authenticated_editor_administrator_or_owner(
|
|||||||
document = models.Document.objects.get(pk=document.pk)
|
document = models.Document.objects.get(pk=document.pk)
|
||||||
document_values = serializers.DocumentSerializer(instance=document).data
|
document_values = serializers.DocumentSerializer(instance=document).data
|
||||||
for key, value in document_values.items():
|
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]
|
assert value == old_document_values[key]
|
||||||
elif key == "updated_at":
|
elif key == "updated_at":
|
||||||
assert value > old_document_values[key]
|
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 = models.Document.objects.get(pk=document.pk)
|
||||||
document_values = serializers.DocumentSerializer(instance=document).data
|
document_values = serializers.DocumentSerializer(instance=document).data
|
||||||
for key, value in document_values.items():
|
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]
|
assert value == old_document_values[key]
|
||||||
elif key == "updated_at":
|
elif key == "updated_at":
|
||||||
assert value > old_document_values[key]
|
assert value > old_document_values[key]
|
||||||
|
|||||||
Reference in New Issue
Block a user