Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #169 from WordPress/clean_endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvkb authored Aug 23, 2021
2 parents fb9280f + 80fc446 commit 1a8f5bc
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 320 deletions.
1 change: 1 addition & 0 deletions openverse-api/catalog/api/examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
recommendations_images_read_curl,
image_detail_curl,
image_stats_curl,
report_image_curl,
)
from catalog.api.examples.image_responses import (
image_search_200_example,
Expand Down
5 changes: 5 additions & 0 deletions openverse-api/catalog/api/examples/image_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,8 @@
# Get the statistics for image sources
curl -H "Authorization: Bearer DLBYIcfnKfolaXKcmMC8RIDCavc2hW" http://api.openverse.engineering/v1/images/stats
""" # noqa

report_image_curl = """
# Report an issue about image ID 7c829a03-fb24-4b57-9b03-65f43ed19395
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer DLBYIcfnKfolaXKcmMC8RIDCavc2hW" -d '{"reason": "mature", "identifier": "7c829a03-fb24-4b57-9b03-65f43ed19395", "description": "This image contains sensitive content"}' https://api.openverse.engineering/v1/images/7c829a03-fb24-4b57-9b03-65f43ed19395/report
""" # noqa
2 changes: 1 addition & 1 deletion openverse-api/catalog/api/serializers/audio_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class AudioSerializer(MediaSerializer):
help_text="A direct link to the detail view of this audio file."
)
related_url = serializers.HyperlinkedIdentityField(
view_name='related-audio',
view_name='audio-related',
lookup_field='identifier',
read_only=True,
help_text="A link to an endpoint that provides similar audio files."
Expand Down
4 changes: 2 additions & 2 deletions openverse-api/catalog/api/serializers/image_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class ImageSerializer(MediaSerializer):
help_text="A direct link to the detail view of this image."
)
related_url = serializers.HyperlinkedIdentityField(
view_name='related-images',
view_name='image-related',
lookup_field='identifier',
read_only=True,
help_text="A link to an endpoint that provides similar images."
Expand All @@ -126,7 +126,7 @@ class ImageSerializer(MediaSerializer):
def get_thumbnail(self, obj):
request = self.context['request']
host = request.get_host()
path = reverse('thumbs', kwargs={'identifier': obj.identifier})
path = reverse('image-thumb', kwargs={'identifier': obj.identifier})
return f'https://{host}{path}'


Expand Down
27 changes: 27 additions & 0 deletions openverse-api/catalog/api/utils/status_code_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View


def get_status_code_view(data, status_code=200):
"""
Get a class-based view that returns the given data and status code on all
HTTP methods. Useful for blanket discontinuation of API endpoints.
:param data: the dictionary to serialize as the JSON response
:param status_code: the status code of the returned response
:return: the class based view that returns the same response for all methods
"""

@method_decorator(csrf_exempt, name='dispatch')
class StatusCodeView(View):
status = status_code

def dispatch(self, request, *args, **kwargs):
return JsonResponse(
status=self.status,
data=data,
)

return StatusCodeView
89 changes: 77 additions & 12 deletions openverse-api/catalog/api/views/image_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
import piexif
import requests
from PIL import Image as img
from django.conf import settings
from django.urls import reverse
from django.http.response import HttpResponse, FileResponse
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status
from rest_framework.generics import GenericAPIView, CreateAPIView
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.views import APIView
from urllib.error import HTTPError
from urllib.request import urlopen

import catalog.api.controllers.search_controller as search_controller
from catalog.api.examples import (
Expand All @@ -29,6 +32,8 @@
oembed_list_404_example,
image_stats_curl,
image_stats_200_example,
report_image_curl,
images_report_create_201_example,
)
from catalog.api.models import Image, ImageReport
from catalog.api.serializers.error_serializers import (
Expand All @@ -44,11 +49,14 @@
OembedSerializer,
OembedResponseSerializer,
AboutImageSerializer,
ProxiedImageSerializer,
)
from catalog.api.utils import ccrel
from catalog.api.utils.throttle import OneThousandPerMinute
from catalog.api.utils.exceptions import input_error_response
from catalog.api.utils.watermark import watermark
from catalog.api.views.media_views import (
refer_sample,
RESULTS,
RESULT_COUNT,
PAGE_COUNT,
Expand Down Expand Up @@ -212,7 +220,7 @@ def get(self, request, identifier, format=None):
# Proxy insecure HTTP images at full resolution.
if 'http://' in resp.data[search_controller.URL]:
secure = request.build_absolute_uri(
reverse('thumbs', [identifier])
reverse('image-thumb', kwargs={'identifier': identifier})
)
secure += '?full_size=True'
resp.data[search_controller.URL] = secure
Expand Down Expand Up @@ -367,22 +375,38 @@ def get(self, request):


class ReportImageView(CreateAPIView):
"""
images_report_create
images_report_create is an API endpoint to report an issue about a
specified image ID to Openverse.
report_image_description = f"""
images_report_create is an API endpoint to report an issue about a specified
image ID to Openverse.
By using this endpoint, you can report an image if it infringes copyright,
contains mature or sensitive content and others.
By using this endpoint, you can report an image if it infringes copyright,
contains mature or sensitive content and others.
{refer_sample}""" # noqa

You can refer to Bash's Request Samples for example on how to use
this endpoint.
""" # noqa
swagger_schema = CustomAutoSchema
queryset = ImageReport.objects.all()
serializer_class = ReportImageSerializer

@swagger_auto_schema(operation_id='images_report_create',
operation_description=report_image_description,
query_serializer=ReportImageSerializer,
responses={
"201": openapi.Response(
description="OK",
examples=images_report_create_201_example,
schema=ReportImageSerializer
)
},
code_examples=[
{
'lang': 'Bash',
'source': report_image_curl,
}
])
def post(self, request, *args, **kwargs):
return super(ReportImageView, self).post(request, *args, **kwargs)


class ImageStats(MediaStats):
image_stats_description = f"""
Expand Down Expand Up @@ -410,3 +434,44 @@ class ImageStats(MediaStats):
])
def get(self, request, format=None):
return self._get(request, 'image')


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

lookup_field = 'identifier'
queryset = Image.objects.all()
throttle_classes = [OneThousandPerMinute]
swagger_schema = None

def get(self, request, identifier, format=None):
serialized = ProxiedImageSerializer(data=request.data)
serialized.is_valid()
try:
image = Image.objects.get(identifier=identifier)
except Image.DoesNotExist:
return Response(status=404, data='Not Found')

if serialized.data['full_size']:
proxy_upstream = f'{settings.THUMBNAIL_PROXY_URL}/{image.url}'
else:
proxy_upstream = f'{settings.THUMBNAIL_PROXY_URL}/' \
f'{settings.THUMBNAIL_WIDTH_PX}' \
f',fit/{image.url}'
try:
upstream_response = urlopen(proxy_upstream)
status = upstream_response.status
content_type = upstream_response.headers.get('Content-Type')
except HTTPError:
log.info('Failed to render thumbnail: ', exc_info=True)
return HttpResponse(status=500)

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

return response
69 changes: 0 additions & 69 deletions openverse-api/catalog/api/views/link_views.py

This file was deleted.

55 changes: 2 additions & 53 deletions openverse-api/catalog/api/views/site_views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import logging as log
import secrets
import smtplib
from urllib.error import HTTPError
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 @@ -14,20 +12,11 @@
ForbiddenErrorSerializer,
InternalServerErrorSerializer,
)
from catalog.api.serializers.image_serializers import ProxiedImageSerializer
from drf_yasg.utils import swagger_auto_schema
from catalog.api.models import (
Image,
ThrottledApplication,
OAuth2Verification,
)
from catalog.api.utils.throttle import (
TenPerDay, OnePerSecond, OneThousandPerMinute
)
from catalog.api.models import ThrottledApplication, OAuth2Verification
from catalog.api.utils.throttle import TenPerDay, OnePerSecond
from catalog.api.utils.oauth2_helper import get_token_info
from catalog.settings import THUMBNAIL_PROXY_URL, THUMBNAIL_WIDTH_PX
from django.core.cache import cache
from django.http import HttpResponse
from drf_yasg import openapi
from catalog.example_responses import (
register_api_oauth2_201_example,
Expand Down Expand Up @@ -327,43 +316,3 @@ def get(self, request, format=None):
'verified': verified
}
return Response(status=200, data=response_data)


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

lookup_field = 'identifier'
queryset = Image.objects.all()
throttle_classes = [OneThousandPerMinute]
swagger_schema = None

def get(self, request, identifier, format=None):
serialized = ProxiedImageSerializer(data=request.data)
serialized.is_valid()
try:
image = Image.objects.get(identifier=identifier)
except Image.DoesNotExist:
return Response(status=404, data='Not Found')

if serialized.data['full_size']:
proxy_upstream = f'{THUMBNAIL_PROXY_URL}/{image.url}'
else:
proxy_upstream = f'{THUMBNAIL_PROXY_URL}/{THUMBNAIL_WIDTH_PX}'\
f',fit/{image.url}'
try:
upstream_response = urlopen(proxy_upstream)
status = upstream_response.status
content_type = upstream_response.headers.get('Content-Type')
except HTTPError:
log.info('Failed to render thumbnail: ', exc_info=True)
return HttpResponse(status=500)

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

return response
Loading

0 comments on commit 1a8f5bc

Please sign in to comment.