♻️(backend) return the full document in the duplicate response

The duplicate endpoint used to respond with only `{"id": ...}`. It now
returns the complete duplicated document representation, consistent
with the other document detail endpoints, so the frontend doesn't have
to make a follow-up request to get the new document's data.

This required setting `is_favorite` explicitly on the duplicated
document before serializing it: it is normally set by the
`annotate_is_favorite` queryset method, which the newly created
document never goes through. Being a read-only serializer field, it
was silently dropped from the response instead of raising an error. A
document can't be a favorite right after being created, so it is set
to `False` directly.
This commit is contained in:
Anthony LC
2026-09-18 16:17:31 +02:00
parent d471fd987e
commit d01372fd90
2 changed files with 34 additions and 2 deletions
+8 -2
View File
@@ -1349,10 +1349,16 @@ class DocumentViewSet(
document=duplicated_document,
)
return drf_response.Response(
{"id": str(duplicated_document.id)}, status=status.HTTP_201_CREATED
# Set the `is_favorite` attribute to False for the duplicated document, as it
# cannot be a favorite immediately after creation.
duplicated_document.is_favorite = False
serializer = serializers.DocumentSerializer(
duplicated_document, context=self.get_serializer_context()
)
return drf_response.Response(serializer.data, status=status.HTTP_201_CREATED)
def _duplicate_document(
self,
document_to_duplicate,
@@ -108,6 +108,8 @@ def test_api_documents_duplicate_success(index):
users=[user, factories.UserFactory()],
title="document with an image",
attachments=[key for key, _ in image_refs],
# The original document is a favorite: the duplicate should not be one
favorited_by=[user],
)
factories.DocumentFactory(id=document_ids[(index + 1) % 3])
# Don't create document for third ID to check that it doesn't impact access to attachments
@@ -131,6 +133,30 @@ def test_api_documents_duplicate_success(index):
assert duplicated_document.get_parent() == document.get_parent()
assert duplicated_document.path == document.get_last_sibling().path
assert response.json() == {
"id": str(duplicated_document.id),
"abilities": duplicated_document.get_abilities(user),
"ancestors_link_reach": None,
"ancestors_link_role": None,
"computed_link_reach": duplicated_document.computed_link_reach,
"computed_link_role": duplicated_document.computed_link_role,
"created_at": duplicated_document.created_at.isoformat().replace("+00:00", "Z"),
"creator": str(user.id),
"deleted_at": None,
"depth": duplicated_document.depth,
"excerpt": duplicated_document.excerpt,
"is_favorite": False,
"link_reach": duplicated_document.link_reach,
"link_role": duplicated_document.link_role,
"nb_accesses_ancestors": duplicated_document.nb_accesses_ancestors,
"nb_accesses_direct": duplicated_document.nb_accesses_direct,
"numchild": 0,
"path": duplicated_document.path,
"title": "Copy of document with an image",
"updated_at": duplicated_document.updated_at.isoformat().replace("+00:00", "Z"),
"user_role": "owner",
}
mock_capture.assert_called_once_with(
"doc_duplicated",
user,