From d01372fd90a109db5b3dd1be74779286ae4c4933 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 16 Sep 2026 16:50:01 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(backend)=20return=20the=20fu?= =?UTF-8?q?ll=20document=20in=20the=20duplicate=20response?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/backend/core/api/viewsets.py | 10 +++++-- .../documents/test_api_documents_duplicate.py | 26 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 298b0cafa..be0a1ceb5 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -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, diff --git a/src/backend/core/tests/documents/test_api_documents_duplicate.py b/src/backend/core/tests/documents/test_api_documents_duplicate.py index b3c5d509c..3420bb9e7 100644 --- a/src/backend/core/tests/documents/test_api_documents_duplicate.py +++ b/src/backend/core/tests/documents/test_api_documents_duplicate.py @@ -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,