Multi-platform: support multiple files per version #201
@ -5,8 +5,9 @@ from django.urls import reverse
|
|||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APITestCase, APIClient
|
from rest_framework.test import APITestCase, APIClient
|
||||||
|
|
||||||
from common.tests.factories.users import UserFactory
|
|
||||||
from common.tests.factories.extensions import create_approved_version, create_version
|
from common.tests.factories.extensions import create_approved_version, create_version
|
||||||
|
from common.tests.factories.files import FileFactory
|
||||||
|
from common.tests.factories.users import UserFactory
|
||||||
from common.tests.utils import create_user_token
|
from common.tests.utils import create_user_token
|
||||||
|
|
||||||
from extensions.models import Extension, Version
|
from extensions.models import Extension, Version
|
||||||
@ -176,6 +177,39 @@ class FiltersTest(APITestCase):
|
|||||||
).json()
|
).json()
|
||||||
self.assertEqual(len(json['data']), 1)
|
self.assertEqual(len(json['data']), 1)
|
||||||
|
|
||||||
|
def test_platform_filter_same_version(self):
|
||||||
|
version = create_approved_version(
|
||||||
|
metadata__id='filter_test',
|
||||||
|
metadata__platforms=['linux-x64'],
|
||||||
|
metadata__version='1.0.0',
|
||||||
|
)
|
||||||
|
version = version.add_file(
|
||||||
|
FileFactory(
|
||||||
|
metadata__id='filter_test',
|
||||||
|
metadata__platforms=['windows-x64'],
|
||||||
|
metadata__version='1.0.0',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
url = reverse('extensions:api')
|
||||||
|
json = self.client.get(
|
||||||
|
url + '?platform=linux-x64',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json['data']), 1)
|
||||||
|
|
||||||
|
json = self.client.get(
|
||||||
|
url + '?platform=windows-x64',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json['data']), 1)
|
||||||
|
|
||||||
|
json = self.client.get(
|
||||||
|
url,
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json['data']), 2)
|
||||||
|
|
||||||
def test_blender_version_filter_latest_not_max_version(self):
|
def test_blender_version_filter_latest_not_max_version(self):
|
||||||
version = create_approved_version(metadata__blender_version_min='4.0.1')
|
version = create_approved_version(metadata__blender_version_min='4.0.1')
|
||||||
date_created = version.date_created
|
date_created = version.date_created
|
||||||
|
@ -54,7 +54,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|||||||
except Platform.DoesNotExist:
|
except Platform.DoesNotExist:
|
||||||
self.platform = self.UNKNOWN_PLATFORM
|
self.platform = self.UNKNOWN_PLATFORM
|
||||||
|
|
||||||
def find_matching_file_and_version(self, instance):
|
def find_matching_files_and_version(self, instance):
|
||||||
# avoid triggering additional db queries, reuse the prefetched queryset
|
# avoid triggering additional db queries, reuse the prefetched queryset
|
||||||
versions = sorted(
|
versions = sorted(
|
||||||
[v for v in instance.versions.all() if v.is_listed],
|
[v for v in instance.versions.all() if v.is_listed],
|
||||||
@ -62,7 +62,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|||||||
reverse=True,
|
reverse=True,
|
||||||
)
|
)
|
||||||
if not versions:
|
if not versions:
|
||||||
return (None, None)
|
return ([], None)
|
||||||
|
|
||||||
for v in versions:
|
for v in versions:
|
||||||
if self.blender_version and not is_in_version_range(
|
if self.blender_version and not is_in_version_range(
|
||||||
@ -71,44 +71,48 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|||||||
v.blender_version_max,
|
v.blender_version_max,
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
if file := v.get_file_for_platform(self.platform):
|
if self.platform:
|
||||||
return (file, v)
|
if file := v.get_file_for_platform(self.platform):
|
||||||
|
return ([file], v)
|
||||||
|
else:
|
||||||
|
return (v.files.all(), v)
|
||||||
|
|
||||||
Oleg-Komarov marked this conversation as resolved
Outdated
|
|||||||
return (None, None)
|
return ([], None)
|
||||||
Oleg-Komarov marked this conversation as resolved
Outdated
Anna Sirota
commented
needs another needs another `break` here
|
|||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
# TODO? return all matching files (when no self.platform is passed)?
|
matching_files, matching_version = self.find_matching_files_and_version(instance)
|
||||||
matching_file, matching_version = self.find_matching_file_and_version(instance)
|
result = []
|
||||||
if not matching_file:
|
for file in matching_files:
|
||||||
return None
|
data = {
|
||||||
data = {
|
'id': instance.extension_id,
|
||||||
'id': instance.extension_id,
|
'schema_version': matching_version.schema_version,
|
||||||
'schema_version': matching_version.schema_version,
|
'name': instance.name,
|
||||||
'name': instance.name,
|
'version': matching_version.version,
|
||||||
'version': matching_version.version,
|
'tagline': matching_version.tagline,
|
||||||
'tagline': matching_version.tagline,
|
'archive_hash': file.original_hash,
|
||||||
'archive_hash': matching_file.original_hash,
|
'archive_size': file.size_bytes,
|
||||||
'archive_size': matching_file.size_bytes,
|
'archive_url': self.request.build_absolute_uri(
|
||||||
'archive_url': self.request.build_absolute_uri(
|
matching_version.get_download_url(
|
||||||
matching_version.get_download_url(
|
platform=self.platform,
|
||||||
platform=self.platform,
|
append_repository_and_compatibility=False,
|
||||||
append_repository_and_compatibility=False,
|
)
|
||||||
)
|
),
|
||||||
),
|
'type': EXTENSION_TYPE_SLUGS_SINGULAR.get(instance.type),
|
||||||
'type': EXTENSION_TYPE_SLUGS_SINGULAR.get(instance.type),
|
'blender_version_min': matching_version.blender_version_min,
|
||||||
'blender_version_min': matching_version.blender_version_min,
|
'blender_version_max': matching_version.blender_version_max,
|
||||||
'blender_version_max': matching_version.blender_version_max,
|
'website': self.request.build_absolute_uri(instance.get_absolute_url()),
|
||||||
'website': self.request.build_absolute_uri(instance.get_absolute_url()),
|
# avoid triggering additional db queries, reuse the prefetched queryset
|
||||||
# avoid triggering additional db queries, reuse the prefetched queryset
|
'maintainer': (
|
||||||
'maintainer': instance.team and instance.team.name or str(instance.authors.all()[0]),
|
instance.team and instance.team.name or str(instance.authors.all()[0])
|
||||||
'license': [license_iter.slug for license_iter in matching_version.licenses.all()],
|
),
|
||||||
'permissions': matching_file.metadata.get('permissions'),
|
'license': [license_iter.slug for license_iter in matching_version.licenses.all()],
|
||||||
# listing all platforms for matching_version, not matching_file (see TODO? above)
|
'permissions': file.metadata.get('permissions'),
|
||||||
'platforms': [platform.slug for platform in matching_version.platforms.all()],
|
'platforms': file.get_platforms(),
|
||||||
# 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()],
|
||||||
}
|
}
|
||||||
return clean_json_dictionary_from_optional_fields(data)
|
result.append(clean_json_dictionary_from_optional_fields(data))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class ExtensionsAPIView(APIView):
|
class ExtensionsAPIView(APIView):
|
||||||
@ -153,7 +157,10 @@ class ExtensionsAPIView(APIView):
|
|||||||
request=request,
|
request=request,
|
||||||
many=True,
|
many=True,
|
||||||
)
|
)
|
||||||
data = [e for e in serializer.data if e is not None]
|
data = []
|
||||||
|
for entry in serializer.data:
|
||||||
|
data.extend(entry)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
'blocklist': Extension.objects.blocklisted.values_list('extension_id', flat=True),
|
'blocklist': Extension.objects.blocklisted.values_list('extension_id', flat=True),
|
||||||
|
Loading…
Reference in New Issue
Block a user
this looks shared with the logic in
public
view that selects which file to pick from storage, and should probable become a utility or method somewhere.