From 419d076b8c0b5a5dec2e57b2cce4072a9f3794e3 Mon Sep 17 00:00:00 2001 From: Anna Sirota Date: Fri, 10 May 2024 13:35:19 +0200 Subject: [PATCH 1/3] API extensions: add `icon_url` and `featured_image_url` --- common/tests/factories/extensions.py | 20 ++++++++++++++++++ extensions/tests/test_submit.py | 2 ++ extensions/tests/test_update.py | 5 ++++- extensions/tests/test_views.py | 6 ++++++ extensions/views/api.py | 31 +++++++++++++++++++++------- 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/common/tests/factories/extensions.py b/common/tests/factories/extensions.py index e897e242..9da99f07 100644 --- a/common/tests/factories/extensions.py +++ b/common/tests/factories/extensions.py @@ -6,6 +6,7 @@ from mdgen import MarkdownPostProvider import factory import factory.fuzzy +from constants.base import FILE_TYPE_CHOICES from extensions.models import Extension, Version, Tag, Preview from ratings.models import Rating @@ -22,6 +23,25 @@ class ExtensionFactory(DjangoModelFactory): description = factory.LazyAttribute( 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, + ) + featured_image = factory.SubFactory( + 'common.tests.factories.files.FileFactory', + original_name=factory.Faker('file_name', extension='jpeg'), + source='images/fo/foobar.jpeg', + original_hash=factory.Faker('lexify', text='hash:??????????????'), + hash=factory.Faker('lexify', text='hash:??????????????'), + type=FILE_TYPE_CHOICES.IMAGE, + size_bytes=4321, + metadata={'thumbnails': {'1080p': {'path': 'images/fo/foobar_1920x1080_random7.webp'}}}, + ) support = factory.Faker('url') website = factory.Faker('url') diff --git a/extensions/tests/test_submit.py b/extensions/tests/test_submit.py index 722be15c..65fe9060 100644 --- a/extensions/tests/test_submit.py +++ b/extensions/tests/test_submit.py @@ -273,6 +273,8 @@ class SubmitFinaliseTest(TestCase): extension__name=file_data['metadata']['name'], extension__slug=file_data['metadata']['id'].replace("_", "-"), extension__website=None, + extension__icon=None, + extension__featured_image=None, tagline=file_data['metadata']['tagline'], version=file_data['metadata']['version'], blender_version_min=file_data['metadata']['blender_version_min'], diff --git a/extensions/tests/test_update.py b/extensions/tests/test_update.py index 38a724b4..d6446357 100644 --- a/extensions/tests/test_update.py +++ b/extensions/tests/test_update.py @@ -97,6 +97,7 @@ class UpdateTest(TestCase): def test_post_upload_multiple_preview_images(self): extension = create_approved_version().extension + images_count_before = File.objects.filter(type=File.TYPES.IMAGE).count() data = { **POST_DATA, @@ -122,7 +123,9 @@ class UpdateTest(TestCase): self.assertEqual(response.status_code, 302, _get_all_form_errors(response)) self.assertEqual(response['Location'], url) 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) file1 = extension.previews.all()[0] file2 = extension.previews.all()[1] diff --git a/extensions/tests/test_views.py b/extensions/tests/test_views.py index 797e8334..dc1a3b1f 100644 --- a/extensions/tests/test_views.py +++ b/extensions/tests/test_views.py @@ -70,6 +70,12 @@ class PublicViewsTest(_BaseTestCase): self.assertIn('license', v) self.assertIn('website', v) self.assertIn('schema_version', v) + self.assertEqual( + v['icon_url'], 'https://extensions.local:8111/media/images/de/deadbeef.png' + ) + self.assertEqual( + v['featured_image_url'], 'https://extensions.local:8111/media/images/fo/foobar.jpeg' + ) return response def test_home_page_view_api(self): diff --git a/extensions/views/api.py b/extensions/views/api.py index 9ea768c3..1b0bd009 100644 --- a/extensions/views/api.py +++ b/extensions/views/api.py @@ -9,6 +9,7 @@ from django.core.exceptions import ValidationError from common.compare import is_in_version_range, version from extensions.models import Extension from extensions.utils import clean_json_dictionary_from_optional_fields +from utils import absolutify from constants.base import ( @@ -68,6 +69,11 @@ class ListedExtensionsSerializer(serializers.ModelSerializer): if not matching_version: return None + icon_url = featured_image_url = None + if instance.icon: + icon_url = absolutify(instance.icon.source.url) + if instance.featured_image: + featured_image_url = absolutify(instance.featured_image.thumbnail_1080p_url) data = { 'id': instance.extension_id, 'schema_version': matching_version.schema_version, @@ -87,6 +93,8 @@ class ListedExtensionsSerializer(serializers.ModelSerializer): 'permissions': [permission.slug for permission in matching_version.permissions.all()], # TODO: handle copyright 'tags': [str(tag) for tag in matching_version.tags.all()], + 'icon_url': icon_url, + 'featured_image_url': featured_image_url, } return clean_json_dictionary_from_optional_fields(data) @@ -106,14 +114,21 @@ class ExtensionsAPIView(APIView): ) def get(self, request): blender_version = request.GET.get('blender_version') - qs = Extension.objects.listed.prefetch_related( - 'authors', - 'versions', - 'versions__file', - 'versions__licenses', - 'versions__permissions', - 'versions__tags', - ).all() + qs = ( + Extension.objects.listed.select_related( + 'icon', + 'featured_image', + ) + .prefetch_related( + 'authors', + 'versions', + 'versions__file', + 'versions__licenses', + 'versions__permissions', + 'versions__tags', + ) + .all() + ) serializer = self.serializer_class( qs, blender_version=blender_version, request=request, many=True ) -- 2.30.2 From 8ba6bd670a6965c0efbdd35e0cf7f327b228cde0 Mon Sep 17 00:00:00 2001 From: Anna Sirota Date: Fri, 10 May 2024 13:40:11 +0200 Subject: [PATCH 2/3] Update tests --- extensions/tests/test_views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/tests/test_views.py b/extensions/tests/test_views.py index dc1a3b1f..e927786d 100644 --- a/extensions/tests/test_views.py +++ b/extensions/tests/test_views.py @@ -74,7 +74,8 @@ class PublicViewsTest(_BaseTestCase): v['icon_url'], 'https://extensions.local:8111/media/images/de/deadbeef.png' ) self.assertEqual( - v['featured_image_url'], 'https://extensions.local:8111/media/images/fo/foobar.jpeg' + v['featured_image_url'], + 'https://extensions.local:8111/media/images/fo/foobar_1920x1080_random7.webp', ) return response -- 2.30.2 From dee031ecd2e706090dbd8347065d08ac64dbee8c Mon Sep 17 00:00:00 2001 From: Anna Sirota Date: Fri, 10 May 2024 14:28:32 +0200 Subject: [PATCH 3/3] Only icon --- common/tests/factories/extensions.py | 10 ---------- extensions/tests/test_submit.py | 1 - extensions/tests/test_views.py | 4 ---- extensions/views/api.py | 12 +++++------- 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/common/tests/factories/extensions.py b/common/tests/factories/extensions.py index 9da99f07..0a21bd07 100644 --- a/common/tests/factories/extensions.py +++ b/common/tests/factories/extensions.py @@ -32,16 +32,6 @@ class ExtensionFactory(DjangoModelFactory): type=FILE_TYPE_CHOICES.IMAGE, size_bytes=1234, ) - featured_image = factory.SubFactory( - 'common.tests.factories.files.FileFactory', - original_name=factory.Faker('file_name', extension='jpeg'), - source='images/fo/foobar.jpeg', - original_hash=factory.Faker('lexify', text='hash:??????????????'), - hash=factory.Faker('lexify', text='hash:??????????????'), - type=FILE_TYPE_CHOICES.IMAGE, - size_bytes=4321, - metadata={'thumbnails': {'1080p': {'path': 'images/fo/foobar_1920x1080_random7.webp'}}}, - ) support = factory.Faker('url') website = factory.Faker('url') diff --git a/extensions/tests/test_submit.py b/extensions/tests/test_submit.py index 65fe9060..f025c642 100644 --- a/extensions/tests/test_submit.py +++ b/extensions/tests/test_submit.py @@ -274,7 +274,6 @@ class SubmitFinaliseTest(TestCase): extension__slug=file_data['metadata']['id'].replace("_", "-"), extension__website=None, extension__icon=None, - extension__featured_image=None, tagline=file_data['metadata']['tagline'], version=file_data['metadata']['version'], blender_version_min=file_data['metadata']['blender_version_min'], diff --git a/extensions/tests/test_views.py b/extensions/tests/test_views.py index e927786d..7a80c728 100644 --- a/extensions/tests/test_views.py +++ b/extensions/tests/test_views.py @@ -73,10 +73,6 @@ class PublicViewsTest(_BaseTestCase): self.assertEqual( v['icon_url'], 'https://extensions.local:8111/media/images/de/deadbeef.png' ) - self.assertEqual( - v['featured_image_url'], - 'https://extensions.local:8111/media/images/fo/foobar_1920x1080_random7.webp', - ) return response def test_home_page_view_api(self): diff --git a/extensions/views/api.py b/extensions/views/api.py index 1b0bd009..2bf9ba0c 100644 --- a/extensions/views/api.py +++ b/extensions/views/api.py @@ -5,6 +5,7 @@ from rest_framework import serializers from rest_framework.views import APIView from drf_spectacular.utils import OpenApiParameter, extend_schema from django.core.exceptions import ValidationError +from django.templatetags.static import static from common.compare import is_in_version_range, version from extensions.models import Extension @@ -69,11 +70,10 @@ class ListedExtensionsSerializer(serializers.ModelSerializer): if not matching_version: return None - icon_url = featured_image_url = None + # Use the same stub image as on the website + icon_path = static('common/images/no-icon.png') if instance.icon: - icon_url = absolutify(instance.icon.source.url) - if instance.featured_image: - featured_image_url = absolutify(instance.featured_image.thumbnail_1080p_url) + icon_path = instance.icon.source.url data = { 'id': instance.extension_id, 'schema_version': matching_version.schema_version, @@ -93,8 +93,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer): 'permissions': [permission.slug for permission in matching_version.permissions.all()], # TODO: handle copyright 'tags': [str(tag) for tag in matching_version.tags.all()], - 'icon_url': icon_url, - 'featured_image_url': featured_image_url, + 'icon_url': absolutify(icon_path), } return clean_json_dictionary_from_optional_fields(data) @@ -117,7 +116,6 @@ class ExtensionsAPIView(APIView): qs = ( Extension.objects.listed.select_related( 'icon', - 'featured_image', ) .prefetch_related( 'authors', -- 2.30.2