WIP: API: add icon_url #122

Closed
Anna Sirota wants to merge 5 commits from api-icon-and-featured-image-url into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 39 additions and 9 deletions

View File

@ -6,6 +6,7 @@ from mdgen import MarkdownPostProvider
import factory import factory
import factory.fuzzy import factory.fuzzy
from constants.base import FILE_TYPE_CHOICES
from extensions.models import Extension, Version, Tag, Preview from extensions.models import Extension, Version, Tag, Preview
from ratings.models import Rating from ratings.models import Rating
@ -22,6 +23,15 @@ class ExtensionFactory(DjangoModelFactory):
description = factory.LazyAttribute( description = factory.LazyAttribute(
lambda _: fake_markdown.post(size=random.choice(('medium', 'large'))) lambda _: fake_markdown.post(size=random.choice(('medium', 'large')))
) )
icon = factory.SubFactory(
'common.tests.factories.files.FileFactory',
original_name=factory.Faker('file_name', extension='png'),
source='images/de/deadbeef.png',
original_hash=factory.Faker('lexify', text='hash:??????????????'),
hash=factory.Faker('lexify', text='hash:??????????????'),
type=FILE_TYPE_CHOICES.IMAGE,
size_bytes=1234,
)
support = factory.Faker('url') support = factory.Faker('url')
website = factory.Faker('url') website = factory.Faker('url')

View File

@ -273,6 +273,7 @@ class SubmitFinaliseTest(TestCase):
extension__name=file_data['metadata']['name'], extension__name=file_data['metadata']['name'],
extension__slug=file_data['metadata']['id'].replace("_", "-"), extension__slug=file_data['metadata']['id'].replace("_", "-"),
extension__website=None, extension__website=None,
extension__icon=None,
tagline=file_data['metadata']['tagline'], tagline=file_data['metadata']['tagline'],
version=file_data['metadata']['version'], version=file_data['metadata']['version'],
blender_version_min=file_data['metadata']['blender_version_min'], blender_version_min=file_data['metadata']['blender_version_min'],

View File

@ -97,6 +97,7 @@ class UpdateTest(TestCase):
def test_post_upload_multiple_preview_images(self): def test_post_upload_multiple_preview_images(self):
extension = create_approved_version().extension extension = create_approved_version().extension
images_count_before = File.objects.filter(type=File.TYPES.IMAGE).count()
data = { data = {
**POST_DATA, **POST_DATA,
@ -122,7 +123,9 @@ class UpdateTest(TestCase):
self.assertEqual(response.status_code, 302, _get_all_form_errors(response)) self.assertEqual(response.status_code, 302, _get_all_form_errors(response))
self.assertEqual(response['Location'], url) self.assertEqual(response['Location'], url)
extension.refresh_from_db() extension.refresh_from_db()
self.assertEqual(File.objects.filter(type=File.TYPES.IMAGE).count(), 2) self.assertEqual(
File.objects.filter(type=File.TYPES.IMAGE).count(), images_count_before + 2
)
self.assertEqual(extension.previews.count(), 2) self.assertEqual(extension.previews.count(), 2)
file1 = extension.previews.all()[0] file1 = extension.previews.all()[0]
file2 = extension.previews.all()[1] file2 = extension.previews.all()[1]

View File

@ -70,6 +70,9 @@ class PublicViewsTest(_BaseTestCase):
self.assertIn('license', v) self.assertIn('license', v)
self.assertIn('website', v) self.assertIn('website', v)
self.assertIn('schema_version', v) self.assertIn('schema_version', v)
self.assertEqual(
v['icon_url'], 'https://extensions.local:8111/media/images/de/deadbeef.png'
)
return response return response
def test_home_page_view_api(self): def test_home_page_view_api(self):

View File

@ -5,10 +5,12 @@ from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from drf_spectacular.utils import OpenApiParameter, extend_schema from drf_spectacular.utils import OpenApiParameter, extend_schema
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.templatetags.static import static
from common.compare import is_in_version_range, version from common.compare import is_in_version_range, version
from extensions.models import Extension from extensions.models import Extension
from extensions.utils import clean_json_dictionary_from_optional_fields from extensions.utils import clean_json_dictionary_from_optional_fields
from utils import absolutify
from constants.base import ( from constants.base import (
@ -68,6 +70,10 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
if not matching_version: if not matching_version:
return None return None
# Use the same stub image as on the website
icon_path = static('common/images/no-icon.png')
if instance.icon:
icon_path = instance.icon.source.url
data = { data = {
'id': instance.extension_id, 'id': instance.extension_id,
'schema_version': matching_version.schema_version, 'schema_version': matching_version.schema_version,
@ -87,6 +93,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
'permissions': [permission.slug for permission in matching_version.permissions.all()], 'permissions': [permission.slug for permission in matching_version.permissions.all()],
# TODO: handle copyright # TODO: handle copyright
'tags': [str(tag) for tag in matching_version.tags.all()], 'tags': [str(tag) for tag in matching_version.tags.all()],
'icon_url': absolutify(icon_path),
} }
return clean_json_dictionary_from_optional_fields(data) return clean_json_dictionary_from_optional_fields(data)
@ -106,14 +113,20 @@ class ExtensionsAPIView(APIView):
) )
def get(self, request): def get(self, request):
blender_version = request.GET.get('blender_version') blender_version = request.GET.get('blender_version')
qs = Extension.objects.listed.prefetch_related( qs = (
Extension.objects.listed.select_related(
'icon',
)
.prefetch_related(
'authors', 'authors',
'versions', 'versions',
'versions__file', 'versions__file',
'versions__licenses', 'versions__licenses',
'versions__permissions', 'versions__permissions',
'versions__tags', 'versions__tags',
).all() )
.all()
)
serializer = self.serializer_class( serializer = self.serializer_class(
qs, blender_version=blender_version, request=request, many=True qs, blender_version=blender_version, request=request, many=True
) )