Thumbnails for images and videos #87
@ -1,3 +1,5 @@
|
|||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
@ -80,6 +82,64 @@ class PublicViewsTest(_BaseTestCase):
|
|||||||
self.assertTemplateUsed(response, 'extensions/home.html')
|
self.assertTemplateUsed(response, 'extensions/home.html')
|
||||||
|
|
||||||
|
|
||||||
|
class ApiViewsTest(_BaseTestCase):
|
||||||
|
def test_blender_version_filter(self):
|
||||||
|
create_approved_version(blender_version_min='4.0.1')
|
||||||
|
create_approved_version(blender_version_min='4.1.1')
|
||||||
|
create_approved_version(blender_version_min='4.2.1')
|
||||||
|
url = reverse('extensions:api')
|
||||||
|
|
||||||
|
json = self.client.get(
|
||||||
|
url + '?blender_version=4.1.1',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json['data']), 2)
|
||||||
|
|
||||||
|
json2 = self.client.get(
|
||||||
|
url + '?blender_version=3.0.1',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json2['data']), 0)
|
||||||
|
|
||||||
|
json3 = self.client.get(
|
||||||
|
url + '?blender_version=4.3.1',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json3['data']), 3)
|
||||||
|
|
||||||
|
def test_blender_version_filter_latest_not_max_version(self):
|
||||||
|
version = create_approved_version(blender_version_min='4.0.1')
|
||||||
|
version.date_created
|
||||||
|
extension = version.extension
|
||||||
|
create_approved_version(
|
||||||
|
blender_version_min='4.2.1',
|
||||||
|
extension=extension,
|
||||||
|
date_created=version.date_created + timedelta(days=1),
|
||||||
|
version='2.0.0',
|
||||||
|
)
|
||||||
|
create_approved_version(
|
||||||
|
blender_version_min='3.0.0',
|
||||||
|
extension=extension,
|
||||||
|
date_created=version.date_created + timedelta(days=2),
|
||||||
|
version='1.0.1',
|
||||||
|
)
|
||||||
|
create_approved_version(
|
||||||
|
blender_version_min='4.2.1',
|
||||||
|
extension=extension,
|
||||||
|
date_created=version.date_created + timedelta(days=3),
|
||||||
|
version='2.0.1',
|
||||||
|
)
|
||||||
|
url = reverse('extensions:api')
|
||||||
|
|
||||||
|
json = self.client.get(
|
||||||
|
url + '?blender_version=4.1.1',
|
||||||
|
HTTP_ACCEPT='application/json',
|
||||||
|
).json()
|
||||||
|
self.assertEqual(len(json['data']), 1)
|
||||||
|
# we are expecting the latest matching, not the maximum version
|
||||||
|
self.assertEqual(json['data'][0]['version'], '1.0.1')
|
||||||
|
|
||||||
|
|
||||||
class ExtensionDetailViewTest(_BaseTestCase):
|
class ExtensionDetailViewTest(_BaseTestCase):
|
||||||
def test_cannot_view_unlisted_extension_anonymously(self):
|
def test_cannot_view_unlisted_extension_anonymously(self):
|
||||||
extension = _create_extension()
|
extension = _create_extension()
|
||||||
|
@ -42,38 +42,51 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|||||||
self.fail('invalid_version')
|
self.fail('invalid_version')
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
blender_version_min = instance.latest_version.blender_version_min
|
matching_version = None
|
||||||
blender_version_max = instance.latest_version.blender_version_max
|
# avoid triggering additional db queries, reuse the prefetched queryset
|
||||||
|
versions = [
|
||||||
# TODO: get the latest valid version
|
v
|
||||||
# For now we skip the extension if the latest version is not in a valid range.
|
for v in instance.versions.all()
|
||||||
if self.blender_version and not is_in_version_range(
|
if v.file and v.file.status in instance.valid_file_statuses
|
||||||
self.blender_version, blender_version_min, blender_version_max
|
]
|
||||||
|
if not versions:
|
||||||
|
return None
|
||||||
|
versions = sorted(versions, key=lambda v: v.date_created, reverse=True)
|
||||||
|
if self.blender_version:
|
||||||
|
for v in versions:
|
||||||
|
if is_in_version_range(
|
||||||
|
self.blender_version,
|
||||||
|
v.blender_version_min,
|
||||||
|
v.blender_version_max,
|
||||||
):
|
):
|
||||||
return {}
|
matching_version = v
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# same as latest_version, but without triggering a new queryset
|
||||||
|
matching_version = versions[0]
|
||||||
|
|
||||||
|
if not matching_version:
|
||||||
|
return None
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'id': instance.extension_id,
|
'id': instance.extension_id,
|
||||||
'schema_version': instance.latest_version.schema_version,
|
'schema_version': matching_version.schema_version,
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'version': instance.latest_version.version,
|
'version': matching_version.version,
|
||||||
'tagline': instance.latest_version.tagline,
|
'tagline': matching_version.tagline,
|
||||||
'archive_hash': instance.latest_version.file.original_hash,
|
'archive_hash': matching_version.file.original_hash,
|
||||||
'archive_size': instance.latest_version.file.size_bytes,
|
'archive_size': matching_version.file.size_bytes,
|
||||||
'archive_url': self.request.build_absolute_uri(instance.latest_version.download_url),
|
'archive_url': self.request.build_absolute_uri(matching_version.download_url),
|
||||||
'type': EXTENSION_TYPE_SLUGS_SINGULAR.get(instance.type),
|
'type': EXTENSION_TYPE_SLUGS_SINGULAR.get(instance.type),
|
||||||
'blender_version_min': instance.latest_version.blender_version_min,
|
'blender_version_min': matching_version.blender_version_min,
|
||||||
'blender_version_max': instance.latest_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()),
|
||||||
'maintainer': str(instance.authors.first()),
|
# avoid triggering additional db queries, reuse the prefetched queryset
|
||||||
'license': [
|
'maintainer': str(instance.authors.all()[0]),
|
||||||
license_iter.slug for license_iter in instance.latest_version.licenses.all()
|
'license': [license_iter.slug for license_iter in matching_version.licenses.all()],
|
||||||
],
|
'permissions': [permission.slug for permission in matching_version.permissions.all()],
|
||||||
'permissions': [
|
|
||||||
permission.slug for permission in instance.latest_version.permissions.all()
|
|
||||||
],
|
|
||||||
# TODO: handle copyright
|
# TODO: handle copyright
|
||||||
'tags': [str(tag) for tag in instance.latest_version.tags.all()],
|
'tags': [str(tag) for tag in matching_version.tags.all()],
|
||||||
}
|
}
|
||||||
|
|
||||||
return clean_json_dictionary_from_optional_fields(data)
|
return clean_json_dictionary_from_optional_fields(data)
|
||||||
@ -93,10 +106,18 @@ 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(
|
||||||
|
'authors',
|
||||||
|
'versions',
|
||||||
|
'versions__file',
|
||||||
|
'versions__licenses',
|
||||||
|
'versions__permissions',
|
||||||
|
'versions__tags',
|
||||||
|
).all()
|
||||||
serializer = self.serializer_class(
|
serializer = self.serializer_class(
|
||||||
Extension.objects.listed, blender_version=blender_version, request=request, many=True
|
qs, blender_version=blender_version, request=request, many=True
|
||||||
)
|
)
|
||||||
data = serializer.data
|
data = [e for e in serializer.data if e is not None]
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
# TODO implement extension blocking by moderators
|
# TODO implement extension blocking by moderators
|
||||||
|
@ -28,11 +28,6 @@ class Command(BaseCommand):
|
|||||||
logger.info(f'{recipient} has unconfirmed email, skipping')
|
logger.info(f'{recipient} has unconfirmed email, skipping')
|
||||||
n.save()
|
n.save()
|
||||||
continue
|
continue
|
||||||
# FIXME test with only internal emails first
|
|
||||||
if not recipient.email.endswith('@blender.org'):
|
|
||||||
logger.info('skipping: not an internal email')
|
|
||||||
n.save()
|
|
||||||
continue
|
|
||||||
n.email_sent = True
|
n.email_sent = True
|
||||||
# first mark as processed, then send: avoid spamming in case of a crash-loop
|
# first mark as processed, then send: avoid spamming in case of a crash-loop
|
||||||
n.save()
|
n.save()
|
||||||
|
Loading…
Reference in New Issue
Block a user