Skip to content

Commit d1432c3

Browse files
codingjoetruongvan
andcommitted
Fix #89 -- Handle invalid container values in DRF
A user may pass any container value to the endpoint, and we need to ensure proper error handling and error messages. Co-authored-by: truongvan <[email protected]>
1 parent c947a5e commit d1432c3

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

pictures/contrib/rest_framework.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22

3+
from django.http import QueryDict
34
from rest_framework import serializers
45

56
__all__ = ["PictureField"]
@@ -34,12 +35,18 @@ def to_representation(self, obj: PictureFieldFile):
3435
},
3536
}
3637
try:
37-
query_params = self.context["request"].GET
38+
query_params: QueryDict = self.context["request"].GET
3839
except KeyError:
3940
pass
4041
else:
4142
ratio = query_params.get(f"{self.source}_ratio")
4243
container = query_params.get(f"{self.source}_container")
44+
try:
45+
container = int(container)
46+
except TypeError:
47+
container = None
48+
except ValueError as e:
49+
raise ValueError(f"Container width is not a number: {container}") from e
4350
breakpoints = {
4451
bp: int(query_params.get(f"{self.source}_{bp}"))
4552
for bp in get_settings().BREAKPOINTS

tests/contrib/test_rest_framework.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,86 @@ def test_to_representation__raise_value_error(
167167
serializer.data["picture"]
168168

169169
assert str(e.value) == "Invalid ratio: 21/11. Choices are: 1/1, 3/2, 16/9"
170+
171+
@pytest.mark.django_db
172+
def test_to_representation__with_container(self, rf, image_upload_file, settings):
173+
settings.PICTURES["USE_PLACEHOLDERS"] = False
174+
175+
profile = models.Profile.objects.create(picture=image_upload_file)
176+
request = rf.get("/")
177+
request.GET._mutable = True
178+
request.GET["picture_ratio"] = "16/9"
179+
request.GET["picture_container"] = "1200"
180+
serializer = ProfileSerializer(profile, context={"request": request})
181+
assert serializer.data["picture"] == {
182+
"url": "/media/testapp/profile/image.jpg",
183+
"width": 800,
184+
"height": 800,
185+
"ratios": {
186+
"16/9": {
187+
"sources": {
188+
"image/webp": {
189+
"800": "/media/testapp/profile/image/16_9/800w.webp",
190+
"100": "/media/testapp/profile/image/16_9/100w.webp",
191+
"200": "/media/testapp/profile/image/16_9/200w.webp",
192+
"300": "/media/testapp/profile/image/16_9/300w.webp",
193+
"400": "/media/testapp/profile/image/16_9/400w.webp",
194+
"500": "/media/testapp/profile/image/16_9/500w.webp",
195+
"600": "/media/testapp/profile/image/16_9/600w.webp",
196+
"700": "/media/testapp/profile/image/16_9/700w.webp",
197+
}
198+
},
199+
"media": "(min-width: 0px) and (max-width: 1199px) 100vw, 1200px",
200+
}
201+
},
202+
}
203+
204+
@pytest.mark.django_db
205+
def test_to_representation__without_container(
206+
self, rf, image_upload_file, settings
207+
):
208+
settings.PICTURES["USE_PLACEHOLDERS"] = False
209+
210+
profile = models.Profile.objects.create(picture=image_upload_file)
211+
request = rf.get("/")
212+
request.GET._mutable = True
213+
request.GET["picture_ratio"] = "16/9"
214+
serializer = ProfileSerializer(profile, context={"request": request})
215+
assert serializer.data["picture"] == {
216+
"url": "/media/testapp/profile/image.jpg",
217+
"width": 800,
218+
"height": 800,
219+
"ratios": {
220+
"16/9": {
221+
"sources": {
222+
"image/webp": {
223+
"800": "/media/testapp/profile/image/16_9/800w.webp",
224+
"100": "/media/testapp/profile/image/16_9/100w.webp",
225+
"200": "/media/testapp/profile/image/16_9/200w.webp",
226+
"300": "/media/testapp/profile/image/16_9/300w.webp",
227+
"400": "/media/testapp/profile/image/16_9/400w.webp",
228+
"500": "/media/testapp/profile/image/16_9/500w.webp",
229+
"600": "/media/testapp/profile/image/16_9/600w.webp",
230+
"700": "/media/testapp/profile/image/16_9/700w.webp",
231+
}
232+
},
233+
"media": "100vw",
234+
}
235+
},
236+
}
237+
238+
@pytest.mark.django_db
239+
def test_to_representation__with_false_str_container(
240+
self, rf, image_upload_file, settings
241+
):
242+
settings.PICTURES["USE_PLACEHOLDERS"] = False
243+
244+
profile = models.Profile.objects.create(picture=image_upload_file)
245+
request = rf.get("/")
246+
request.GET._mutable = True
247+
request.GET["picture_ratio"] = "16/9"
248+
request.GET["picture_container"] = "not_a_number"
249+
serializer = ProfileSerializer(profile, context={"request": request})
250+
with pytest.raises(ValueError) as e:
251+
serializer.data["picture"]
252+
assert str(e.value) == "Container width is not a number: not_a_number"

0 commit comments

Comments
 (0)