Skip to content

Commit

Permalink
Merge pull request cc-archive#488 from creativecommons/outloudvi-proxy
Browse files Browse the repository at this point in the history
Outloudvi thumbnail proxy
  • Loading branch information
aldenstpage committed May 6, 2020
2 parents 35e905a + 8e00441 commit f47bd7a
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 10 deletions.
14 changes: 8 additions & 6 deletions cccatalog-api/cccatalog/api/controllers/search_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from elasticsearch_dsl.query import Query
from cccatalog import settings
from django.core.cache import cache
from django.urls import reverse
import cccatalog.api.models as models
import logging as log
from rest_framework import serializers
from cccatalog.settings import THUMBNAIL_PROXY_URL, PROXY_THUMBS
from cccatalog.settings import PROXY_THUMBS
from cccatalog.api.utils.validate_images import validate_images
from cccatalog.api.utils.dead_link_mask import get_query_mask, get_query_hash
from itertools import accumulate
Expand All @@ -21,7 +22,6 @@
DEAD_LINK_RATIO = 1 / 2
THUMBNAIL = 'thumbnail'
URL = 'url'
THUMBNAIL_WIDTH_PX = 600
PROVIDER = 'provider'
DEEP_PAGINATION_ERROR = 'Deep pagination is not allowed.'
QUERY_SPECIAL_CHARACTER_ERROR = 'Unescaped special characters are not allowed.'
Expand Down Expand Up @@ -128,10 +128,12 @@ def _post_process_results(s, start, end, page_size, search_results,
else:
to_proxy = URL
original = res[to_proxy]
proxied = '{proxy_url}/{width}/{original}'.format(
proxy_url=THUMBNAIL_PROXY_URL,
width=THUMBNAIL_WIDTH_PX,
original=original
ext = res["url"].split(".")[-1]
proxied = "http://{}{}".format(
request.get_host(),
reverse('thumbs', kwargs={
'identifier': "{}.{}".format(res["identifier"], ext)
})
)
res[THUMBNAIL] = proxied
results.append(res)
Expand Down
52 changes: 51 additions & 1 deletion cccatalog-api/cccatalog/api/views/site_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging as log
import secrets
import smtplib
from urllib.request import urlopen
from django.core.mail import send_mail
from rest_framework.response import Response
from rest_framework.reverse import reverse
Expand All @@ -10,11 +11,13 @@
from cccatalog.api.serializers.oauth2_serializers import\
OAuth2RegistrationSerializer, OAuth2RegistrationSuccessful, OAuth2KeyInfo
from drf_yasg.utils import swagger_auto_schema
from cccatalog.api.models import ContentProvider
from cccatalog.api.models import ContentProvider, Image
from cccatalog.api.models import ThrottledApplication, OAuth2Verification
from cccatalog.api.utils.throttle import TenPerDay, OnePerSecond
from cccatalog.api.utils.oauth2_helper import get_token_info
from cccatalog.settings import THUMBNAIL_PROXY_URL, THUMBNAIL_WIDTH_PX
from django.core.cache import cache
from django.http import HttpResponse

IDENTIFIER = 'provider_identifier'
NAME = 'provider_name'
Expand Down Expand Up @@ -285,3 +288,50 @@ def get(self, request, format=None):
'verified': verified
}
return Response(status=200, data=response_data)


class Thumbs(APIView):
"""
Return the thumb of an image.
"""

lookup_field = 'identifier'
queryset = Image.objects.all()

@swagger_auto_schema(operation_id="thumb_lookup",
responses={
200: 'The thumb of an image',
400: 'Bad Request',
404: 'Not Found'
})
def get(self, request, identifier, format=None):
path_element = identifier.split(".")
identifier = path_element[0]
extname = ""
if len(path_element) == 2:
extname = path_element[1]
elif len(path_element) > 2:
return Response(status=400)
try:
image = Image.objects.get(identifier=identifier)
if extname and image.url.split(".")[-1] != extname:
return Response(status=404, data='Not Found')
except Image.DoesNotExist:
return Response(status=404, data='Not Found')

upstream_url = '{proxy_url}/{width}/{original}'.format(
proxy_url=THUMBNAIL_PROXY_URL,
width=THUMBNAIL_WIDTH_PX,
original=image.url
)
upstream_response = urlopen(upstream_url)
status = upstream_response.status
content_type = upstream_response.headers.get('Content-Type')

response = HttpResponse(
upstream_response.read(),
status=status,
content_type=content_type
)

return response
6 changes: 4 additions & 2 deletions cccatalog-api/cccatalog/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@
}

# Produce CC-hosted thumbnails dynamically through a proxy.
PROXY_THUMBS = bool(os.environ.get('PROXY_THUMBS', False))
PROXY_THUMBS = bool(os.environ.get('PROXY_THUMBS', True))
THUMBNAIL_PROXY_URL = os.environ.get(
'THUMBNAIL_PROXY_URL', 'https://localhost:8222'
'THUMBNAIL_PROXY_URL', 'http://localhost:8222'
)

THUMBNAIL_WIDTH_PX = 600

AUTHENTICATION_BACKENDS = (
'oauth2_provider.backends.OAuth2Backend',
'django.contrib.auth.backends.ModelBackend',
Expand Down
3 changes: 2 additions & 1 deletion cccatalog-api/cccatalog/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from cccatalog.api.views.image_views import SearchImages, ImageDetail,\
Watermark, RelatedImage, OembedView, ReportImageView
from cccatalog.api.views.site_views import HealthCheck, ImageStats, Register, \
CheckRates, VerifyEmail
CheckRates, VerifyEmail, Thumbs
from cccatalog.api.views.link_views import CreateShortenedLink, \
ResolveShortenedLink
from cccatalog.settings import API_VERSION, WATERMARK_ENABLED
Expand Down Expand Up @@ -110,6 +110,7 @@
),
path('link', CreateShortenedLink.as_view(), name='make-link'),
path('link/<str:path>', ResolveShortenedLink.as_view(), name='resolve'),
path('thumbs/<str:identifier>', Thumbs.as_view(), name='thumbs'),
path('oembed', OembedView.as_view(), name='oembed')
]
if WATERMARK_ENABLED:
Expand Down
6 changes: 6 additions & 0 deletions cccatalog-api/test/v1_integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ def test_image_delete(search_fixture):
deleted_response = requests.get(f'{API_URL}/image/{test_id}')
assert deleted_response.status_code == 404

@pytest.fixture
def test_image_thumb(search_fixture):
thumbnail_url = search_fixture['results'][0]['thumbnail']
thumbnail_response = requests.get(thumbnail_url)
assert thumbnail_response.status_code == 200
assert thumbnail_response.headers["Content-Type"].startswith("image/")

@pytest.fixture
def link_shortener_fixture(search_fixture):
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ services:
ELASTICSEARCH_PORT: "9200"
DISABLE_GLOBAL_THROTTLING: "True"
ROOT_SHORTENING_URL: "localhost:8000"
THUMBNAIL_PROXY_URL: "http://thumbs:8222"
stdin_open: true
tty: true

Expand Down

0 comments on commit f47bd7a

Please sign in to comment.