Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Watermark exception #3019

Merged
merged 11 commits into from
Nov 3, 2023
19 changes: 17 additions & 2 deletions api/api/utils/watermark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
from textwrap import wrap

from django.conf import settings
from rest_framework import status
from rest_framework.exceptions import APIException

import requests
from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw, ImageFont, UnidentifiedImageError
from sentry_sdk import capture_exception


Expand All @@ -25,6 +27,14 @@
}


class UpstreamWatermarkException(APIException):
status_code = status.HTTP_424_FAILED_DEPENDENCY
default_detail = (
"Could not render watermarked image due to upstream provider error."
)
default_code = "upstream_watermark_failure"


class Dimension(Flag):
"""This enum represents the two dimensions of an image."""

Expand Down Expand Up @@ -169,12 +179,17 @@ def _open_image(url):
logger = parent_logger.getChild("_open_image")
try:
response = requests.get(url, headers=HEADERS)
response.raise_for_status()
img_bytes = BytesIO(response.content)
img = Image.open(img_bytes)
except requests.exceptions.RequestException as e:
capture_exception(e)
logger.error(f"Error requesting image: {e}")
raise UpstreamWatermarkException(f"{e}")
except UnidentifiedImageError as e:
capture_exception(e)
logger.error(f"Error loading image data: {e}")
return None, None
raise UpstreamWatermarkException(f"{e}")

return img, img.getexif()

Expand Down
29 changes: 29 additions & 0 deletions api/test/unit/views/test_image_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.http import HttpResponse

import pytest
from PIL import UnidentifiedImageError
from requests import Request, Response

from api.views.image_views import ImageViewSet
Expand Down Expand Up @@ -79,3 +80,31 @@ def test_thumbnail_uses_upstream_thumb_for_smk(
thumb_call.return_value = mock_response
api_client.get(f"/v1/images/{image.identifier}/thumb/")
thumb_call.assert_called_once_with(ANY, image, expected_thumb_url)


@pytest.mark.django_db
def test_watermark_raises_424_for_invalid_image(api_client):
image = ImageFactory.create()
expected_error_message = (
"cannot identify image file <_io.BytesIO object at 0xffff86d8fec0>"
)

with patch("PIL.Image.open") as mock_open:
mock_open.side_effect = UnidentifiedImageError(expected_error_message)
res = api_client.get(f"/v1/images/{image.identifier}/watermark/")
assert res.status_code == 424
assert res.data["detail"] == expected_error_message
obulat marked this conversation as resolved.
Show resolved Hide resolved


@pytest.mark.django_db
def test_watermark_raises_424_for_404_image(api_client):
image = ImageFactory.create()

with patch("requests.get") as mock_get:
mock_get.return_value = Response()
mock_get.return_value.status_code = 404
mock_get.return_value.url = image.url
mock_get.return_value.reason = "Not Found"
res = api_client.get(f"/v1/images/{image.identifier}/watermark/")
assert res.status_code == 424
assert res.data["detail"] == f"404 Client Error: Not Found for url: {image.url}"