Multi-platform: support multiple files per version #201
@ -1,4 +1,5 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
from urllib.parse import urlencode
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
@ -754,14 +755,55 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
|||||||
permissions.append({'slug': slug, 'reason': reason, 'name': all_permission_names[slug]})
|
permissions.append({'slug': slug, 'reason': reason, 'name': all_permission_names[slug]})
|
||||||
return permissions
|
return permissions
|
||||||
|
|
||||||
|
def _get_download_name(self) -> str:
|
||||||
|
"""Return a file name for downloads."""
|
||||||
|
replace_char = f'{self}'.replace('.', '-')
|
||||||
|
return f'{utils.slugify(replace_char)}.zip'
|
||||||
|
|
||||||
|
def get_download_url(self, platform=None, append_repository_and_compatibility=True) -> str:
|
||||||
|
filename = f'{self.extension.type_slug_singular}-{self.extension.slug}-v{self.version}.zip'
|
||||||
|
if platform:
|
||||||
|
download_url = reverse(
|
||||||
|
'extensions:version-platform-download',
|
||||||
|
kwargs={
|
||||||
|
'type_slug': self.extension.type_slug,
|
||||||
|
'slug': self.extension.slug,
|
||||||
|
'version': self.version,
|
||||||
|
'platform': platform,
|
||||||
|
'filename': filename,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
download_url = reverse(
|
||||||
|
'extensions:version-download',
|
||||||
|
kwargs={
|
||||||
|
'type_slug': self.extension.type_slug,
|
||||||
|
'slug': self.extension.slug,
|
||||||
|
'version': self.version,
|
||||||
|
'filename': filename,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if append_repository_and_compatibility:
|
||||||
|
params = {
|
||||||
|
'repository': '/api/v1/extensions/',
|
||||||
|
'blender_version_min': self.blender_version_min,
|
||||||
|
}
|
||||||
|
if self.blender_version_max:
|
||||||
|
params['blender_version_max'] = self.blender_version_max
|
||||||
|
if platforms := self.platforms.all():
|
||||||
|
params['platforms'] = ','.join([p.slug for p in platforms])
|
||||||
|
query_string = urlencode(params)
|
||||||
|
download_url += f'?{query_string}'
|
||||||
|
return download_url
|
||||||
|
|
||||||
def get_download_list(self) -> List[dict]:
|
def get_download_list(self) -> List[dict]:
|
||||||
files = list(self.files.all())
|
files = list(self.files.all())
|
||||||
if len(files) == 1:
|
if len(files) == 1:
|
||||||
file = files[0]
|
file = files[0]
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'name': file.download_name(),
|
'name': self._get_download_name(),
|
||||||
'url': file.download_url(platform=None),
|
'url': self.get_download_url(platform=None),
|
||||||
'size': file.size_bytes,
|
'size': file.size_bytes,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -778,8 +820,8 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'platform': p,
|
'platform': p,
|
||||||
'name': file.download_name(),
|
'name': self._get_download_name(),
|
||||||
'url': file.download_url(platform=p),
|
'url': self.get_download_url(platform=p),
|
||||||
'size': file.size_bytes,
|
'size': file.size_bytes,
|
||||||
}
|
}
|
||||||
for p, file in platform2file.items()
|
for p, file in platform2file.items()
|
||||||
|
@ -92,7 +92,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
|||||||
'archive_hash': matching_file.original_hash,
|
'archive_hash': matching_file.original_hash,
|
||||||
'archive_size': matching_file.size_bytes,
|
'archive_size': matching_file.size_bytes,
|
||||||
'archive_url': self.request.build_absolute_uri(
|
'archive_url': self.request.build_absolute_uri(
|
||||||
matching_file.download_url(
|
matching_version.download_url(
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
append_repository_and_compatibility=False,
|
append_repository_and_compatibility=False,
|
||||||
)
|
)
|
||||||
|
@ -63,9 +63,12 @@ def extension_version_download(request, type_slug, slug, version, filename):
|
|||||||
def extension_version_platform_download(request, type_slug, slug, version, platform, filename):
|
def extension_version_platform_download(request, type_slug, slug, version, platform, filename):
|
||||||
"""Download an extension version and count downloads.
|
"""Download an extension version and count downloads.
|
||||||
|
|
||||||
|
This method processes urls constructed by Version.get_download_list.
|
||||||
|
|
||||||
The `filename` parameter is used to pass a file name ending with `.zip`.
|
The `filename` parameter is used to pass a file name ending with `.zip`.
|
||||||
This is a convention Blender uses to initiate an extension installation on an HTML anchor
|
This is a convention Blender uses to initiate an extension installation on an HTML anchor
|
||||||
drag&drop.
|
drag&drop.
|
||||||
|
Also see $arg_filename usage in playbooks/templates/nginx/http.conf
|
||||||
"""
|
"""
|
||||||
extension_version = get_object_or_404(Version, extension__slug=slug, version=version)
|
extension_version = get_object_or_404(Version, extension__slug=slug, version=version)
|
||||||
ExtensionDownload.create_from_request(request, object_id=extension_version.extension_id)
|
ExtensionDownload.create_from_request(request, object_id=extension_version.extension_id)
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
from urllib.parse import urlencode
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from common.model_mixins import CreatedModifiedMixin, TrackChangesMixin
|
from common.model_mixins import CreatedModifiedMixin, TrackChangesMixin
|
||||||
from files.utils import get_sha256, guess_mimetype_from_ext, get_thumbnail_upload_to
|
from files.utils import get_sha256, guess_mimetype_from_ext, get_thumbnail_upload_to
|
||||||
@ -204,49 +202,6 @@ class File(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
|||||||
'tags': data.get('tags'),
|
'tags': data.get('tags'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def download_name(self) -> str:
|
|
||||||
"""Return a file name for downloads."""
|
|
||||||
version = self.version.first()
|
|
||||||
replace_char = f'{version}'.replace('.', '-')
|
|
||||||
return f'{utils.slugify(replace_char)}.zip'
|
|
||||||
|
|
||||||
def download_url(self, platform=None, append_repository_and_compatibility=True) -> str:
|
|
||||||
filename = self.download_name()
|
|
||||||
version = self.version.first()
|
|
||||||
if platform:
|
|
||||||
download_url = reverse(
|
|
||||||
'extensions:version-platform-download',
|
|
||||||
kwargs={
|
|
||||||
'type_slug': version.extension.type_slug,
|
|
||||||
'slug': version.extension.slug,
|
|
||||||
'version': version.version,
|
|
||||||
'platform': platform,
|
|
||||||
'filename': filename,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
download_url = reverse(
|
|
||||||
'extensions:version-download',
|
|
||||||
kwargs={
|
|
||||||
'type_slug': version.extension.type_slug,
|
|
||||||
'slug': version.extension.slug,
|
|
||||||
'version': version.version,
|
|
||||||
'filename': filename,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if append_repository_and_compatibility:
|
|
||||||
params = {
|
|
||||||
'repository': '/api/v1/extensions/',
|
|
||||||
'blender_version_min': version.blender_version_min,
|
|
||||||
}
|
|
||||||
if version.blender_version_max:
|
|
||||||
params['blender_version_max'] = version.blender_version_max
|
|
||||||
if platforms := self.platforms():
|
|
||||||
params['platforms'] = ','.join(platforms)
|
|
||||||
query_string = urlencode(params)
|
|
||||||
download_url += f'?{query_string}'
|
|
||||||
return download_url
|
|
||||||
|
|
||||||
def get_thumbnail_of_size(self, size_key: str) -> str:
|
def get_thumbnail_of_size(self, size_key: str) -> str:
|
||||||
"""Return absolute path portion of the URL of a thumbnail of this file.
|
"""Return absolute path portion of the URL of a thumbnail of this file.
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class TestTasks(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
response = self.client.get(version.extension.get_versions_url())
|
response = self.client.get(version.extension.get_versions_url())
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
response = self.client.get(version.files.first().download_url())
|
response = self.client.get(version.download_url())
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response['Location'],
|
response['Location'],
|
||||||
|
Loading…
Reference in New Issue
Block a user