108 lines
3.8 KiB
Python
108 lines
3.8 KiB
Python
import logging
|
|
|
|
from rest_framework.response import Response
|
|
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 common.compare import is_in_version_range, version
|
|
from extensions.models import Extension
|
|
from extensions.utils import clean_json_dictionary_from_optional_fields
|
|
|
|
|
|
from constants.base import (
|
|
EXTENSION_TYPE_SLUGS_SINGULAR,
|
|
)
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|
error_messages = {
|
|
"invalid_version": "Invalid version: use full semantic versioning like 4.2.0."
|
|
}
|
|
|
|
class Meta:
|
|
model = Extension
|
|
fields = ()
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.request = kwargs.pop('request', None)
|
|
self.blender_version = kwargs.pop('blender_version', None)
|
|
self._validate()
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def _validate(self):
|
|
if self.blender_version is None:
|
|
return
|
|
try:
|
|
version(self.blender_version)
|
|
except ValidationError:
|
|
self.fail('invalid_version')
|
|
|
|
def to_representation(self, instance):
|
|
blender_version_min = instance.latest_version.blender_version_min
|
|
blender_version_max = instance.latest_version.blender_version_max
|
|
|
|
# TODO: get the latest valid version
|
|
# For now we skip the extension if the latest version is not in a valid range.
|
|
if self.blender_version and not is_in_version_range(
|
|
self.blender_version, blender_version_min, blender_version_max
|
|
):
|
|
return {}
|
|
|
|
data = {
|
|
'id': instance.extension_id,
|
|
'schema_version': instance.latest_version.schema_version,
|
|
'name': instance.name,
|
|
'version': instance.latest_version.version,
|
|
'tagline': instance.latest_version.tagline,
|
|
'archive_hash': instance.latest_version.file.original_hash,
|
|
'archive_size': instance.latest_version.file.size_bytes,
|
|
'archive_url': self.request.build_absolute_uri(instance.latest_version.download_url),
|
|
'type': EXTENSION_TYPE_SLUGS_SINGULAR.get(instance.type),
|
|
'blender_version_min': instance.latest_version.blender_version_min,
|
|
'blender_version_max': instance.latest_version.blender_version_max,
|
|
'website': self.request.build_absolute_uri(instance.get_absolute_url()),
|
|
'maintainer': str(instance.authors.first()),
|
|
'license': [
|
|
license_iter.slug for license_iter in instance.latest_version.licenses.all()
|
|
],
|
|
'permissions': [
|
|
permission.slug for permission in instance.latest_version.permissions.all()
|
|
],
|
|
# TODO: handle copyright
|
|
'tags': [str(tag) for tag in instance.latest_version.tags.all()],
|
|
}
|
|
|
|
return clean_json_dictionary_from_optional_fields(data)
|
|
|
|
|
|
class ExtensionsAPIView(APIView):
|
|
serializer_class = ListedExtensionsSerializer
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
OpenApiParameter(
|
|
name="blender_version",
|
|
description=("Blender version to check for compatibility"),
|
|
type=str,
|
|
)
|
|
]
|
|
)
|
|
def get(self, request):
|
|
blender_version = request.GET.get('blender_version')
|
|
serializer = self.serializer_class(
|
|
Extension.objects.listed, blender_version=blender_version, request=request, many=True
|
|
)
|
|
data = serializer.data
|
|
return Response(
|
|
{
|
|
# TODO implement extension blocking by moderators
|
|
'blocklist': [],
|
|
'data': data,
|
|
'version': 'v1',
|
|
}
|
|
)
|