Skip to content

Commit 2c3eef4

Browse files
committed
✨(api) allow forcing ID when creating a document via API endpoint
We need to be able to force the ID when creating a document via the API endpoint. This is usefull for documents that are created offline as synchronization is achieved by replaying stacked requests. We do it via the serializer, making sure that we don't override an existing document.
1 parent dec1a1a commit 2c3eef4

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ and this project adheres to
2020
- 🛂(backend) stop to list public doc to everyone #234
2121
- 🚚(frontend) change visibility in share modal #235
2222

23+
## Fixed
24+
25+
- 🐛 Fix forcing ID when creating a document via API endpoint #234
26+
2327

2428
## [1.3.0] - 2024-09-05
2529

src/backend/core/api/serializers.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,29 @@ class Meta:
163163
"updated_at",
164164
]
165165

166+
def get_fields(self):
167+
"""Dynamically make `id` read-only on PUT requests but writable on POST requests."""
168+
fields = super().get_fields()
169+
170+
request = self.context.get("request")
171+
if request and request.method == "POST":
172+
fields["id"].read_only = False
173+
174+
return fields
175+
176+
def validate_id(self, value):
177+
"""Ensure the provided ID does not already exist when creating a new document."""
178+
request = self.context.get("request")
179+
180+
# Only check this on POST (creation)
181+
if request and request.method == "POST":
182+
if models.Document.objects.filter(id=value).exists():
183+
raise serializers.ValidationError(
184+
"A document with this ID already exists. You cannot override it."
185+
)
186+
187+
return value
188+
166189

167190
class LinkDocumentSerializer(BaseResourceSerializer):
168191
"""

src/backend/core/tests/documents/test_api_documents_create.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
Tests for Documents API endpoint in impress's core app: create
33
"""
44

5+
from uuid import uuid4
6+
57
import pytest
68
from rest_framework.test import APIClient
79

@@ -46,3 +48,51 @@ def test_api_documents_create_authenticated():
4648
document = Document.objects.get()
4749
assert document.title == "my document"
4850
assert document.accesses.filter(role="owner", user=user).exists()
51+
52+
53+
def test_api_documents_create_force_id_success():
54+
"""It should be possible to force the document ID when creating a document."""
55+
user = factories.UserFactory()
56+
client = APIClient()
57+
client.force_login(user)
58+
59+
forced_id = uuid4()
60+
61+
response = client.post(
62+
"/api/v1.0/documents/",
63+
{
64+
"id": str(forced_id),
65+
"title": "my document",
66+
},
67+
format="json",
68+
)
69+
70+
assert response.status_code == 201
71+
documents = Document.objects.all()
72+
assert len(documents) == 1
73+
assert documents[0].id == forced_id
74+
75+
76+
def test_api_documents_create_force_id_existing():
77+
"""
78+
It should not be possible to use the ID of an existing document when forcing ID on creation.
79+
"""
80+
user = factories.UserFactory()
81+
client = APIClient()
82+
client.force_login(user)
83+
84+
document = factories.DocumentFactory()
85+
86+
response = client.post(
87+
"/api/v1.0/documents/",
88+
{
89+
"id": str(document.id),
90+
"title": "my document",
91+
},
92+
format="json",
93+
)
94+
95+
assert response.status_code == 400
96+
assert response.json() == {
97+
"id": ["A document with this ID already exists. You cannot override it."]
98+
}

0 commit comments

Comments
 (0)