extensions-website/extensions/views/api.py
Oleg-Komarov 40a8d8209e update API response structure #71 (#76)
Reviewed-on: #76
Reviewed-by: Anna Sirota <railla@noreply.localhost>
2024-04-11 14:54:40 +02:00

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',
}
)