Multi-platform: support multiple files per version #201
@ -773,36 +773,22 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
||||
permissions.append({'slug': slug, 'reason': reason, 'name': all_permission_names[slug]})
|
||||
return permissions
|
||||
|
||||
def _get_download_name(self, platform=None) -> str:
|
||||
def _get_download_name(self, file) -> str:
|
||||
"""Return a file name for downloads."""
|
||||
parts = [self.extension.type_slug_singular, self.extension.slug, f'v{self.version}']
|
||||
if platform:
|
||||
parts.append(platform)
|
||||
if platforms := file.get_platforms():
|
||||
parts.extend(platforms)
|
||||
return f'{"-".join(parts)}.zip'
|
||||
|
||||
def get_download_url(self, platform=None, append_repository_and_compatibility=True) -> str:
|
||||
filename = self._get_download_name(platform=platform)
|
||||
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,
|
||||
},
|
||||
)
|
||||
def get_download_url(self, file, append_repository_and_compatibility=True) -> str:
|
||||
filename = self._get_download_name(file)
|
||||
download_url = reverse(
|
||||
'extensions:download',
|
||||
kwargs={
|
||||
'filehash': file.hash,
|
||||
'filename': filename,
|
||||
},
|
||||
)
|
||||
if append_repository_and_compatibility:
|
||||
params = {
|
||||
'repository': '/api/v1/extensions/',
|
||||
@ -810,10 +796,8 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
||||
}
|
||||
if self.blender_version_max:
|
||||
params['blender_version_max'] = self.blender_version_max
|
||||
if platform:
|
||||
params['platforms'] = platform
|
||||
elif platforms := self.platforms.all():
|
||||
params['platforms'] = ','.join([p.slug for p in platforms])
|
||||
if platforms := file.get_platforms():
|
||||
params['platforms'] = ','.join(platforms)
|
||||
Oleg-Komarov marked this conversation as resolved
Outdated
|
||||
query_string = urlencode(params)
|
||||
download_url += f'?{query_string}'
|
||||
return download_url
|
||||
@ -824,9 +808,9 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
||||
file = files[0]
|
||||
return [
|
||||
{
|
||||
'name': self._get_download_name(platform=None),
|
||||
'name': self._get_download_name(file),
|
||||
'size': file.size_bytes,
|
||||
'url': self.get_download_url(platform=None),
|
||||
'url': self.get_download_url(file),
|
||||
}
|
||||
]
|
||||
platform2file = {}
|
||||
@ -841,10 +825,10 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
||||
platform2file[platform] = file
|
||||
return [
|
||||
{
|
||||
'name': self._get_download_name(platform=p),
|
||||
'name': self._get_download_name(file),
|
||||
'platform': p,
|
||||
'size': file.size_bytes,
|
||||
'url': self.get_download_url(platform=p),
|
||||
'url': self.get_download_url(file),
|
||||
}
|
||||
for p, file in platform2file.items()
|
||||
]
|
||||
@ -853,15 +837,12 @@ class Version(CreatedModifiedMixin, TrackChangesMixin, models.Model):
|
||||
build_list = []
|
||||
for file in self.files.all():
|
||||
platforms = file.get_platforms() or []
|
||||
platform = len(platforms) and platforms[0] or None
|
||||
# if file has multiple platforms, picking the first one should still produce a correct
|
||||
# download_url
|
||||
build_list.append(
|
||||
{
|
||||
'name': self._get_download_name(platform=platform),
|
||||
'name': self._get_download_name(file),
|
||||
'platforms': platforms,
|
||||
'size': file.size_bytes,
|
||||
'url': self.get_download_url(platform=platform),
|
||||
'url': self.get_download_url(file),
|
||||
}
|
||||
)
|
||||
return build_list
|
||||
|
@ -28,6 +28,7 @@ urlpatterns = [
|
||||
path('search/', public.SearchView.as_view(), name='search'),
|
||||
path('tag/<slug:tag_slug>/', public.SearchView.as_view(), name='by-tag'),
|
||||
path('team/<slug:team_slug>/', public.SearchView.as_view(), name='by-team'),
|
||||
path('download/<filehash>/<filename>', public.file_download, name='download'),
|
||||
re_path(
|
||||
rf'^(?P<type_slug>{EXTENSION_SLUGS_PATH})/',
|
||||
include(
|
||||
@ -91,11 +92,6 @@ urlpatterns = [
|
||||
public.extension_version_download,
|
||||
name='version-download',
|
||||
),
|
||||
path(
|
||||
'<slug:slug>/<version>/<platform>/download/<filename>',
|
||||
public.extension_version_platform_download,
|
||||
name='version-platform-download',
|
||||
),
|
||||
path('<slug:slug>/versions/', manage.VersionsView.as_view(), name='versions'),
|
||||
],
|
||||
),
|
||||
|
@ -93,7 +93,7 @@ class ListedExtensionsSerializer(serializers.ModelSerializer):
|
||||
'archive_size': file.size_bytes,
|
||||
'archive_url': self.request.build_absolute_uri(
|
||||
matching_version.get_download_url(
|
||||
platform=self.platform,
|
||||
file,
|
||||
append_repository_and_compatibility=False,
|
||||
)
|
||||
),
|
||||
|
@ -4,21 +4,19 @@ import logging
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import connection
|
||||
from django.db.models import Count, Q
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
||||
from extensions.models import Extension, Version, Tag
|
||||
from constants.base import (
|
||||
EXTENSION_TYPE_SLUGS,
|
||||
EXTENSION_TYPE_PLURAL,
|
||||
EXTENSION_TYPE_CHOICES,
|
||||
)
|
||||
from stats.models import ExtensionView
|
||||
from extensions.models import Extension, Version, Tag
|
||||
from files.models import File
|
||||
from stats.models import ExtensionDownload, ExtensionView, VersionDownload
|
||||
import ratings.models
|
||||
|
||||
from stats.models import ExtensionDownload, VersionDownload
|
||||
import teams.models
|
||||
|
||||
User = get_user_model()
|
||||
@ -53,14 +51,16 @@ class HomeView(ListedExtensionsView):
|
||||
|
||||
|
||||
def extension_version_download(request, type_slug, slug, version, filename):
|
||||
"""A backward-compatible shortcut for the method below.
|
||||
"""A backward-compatible url for downloads.
|
||||
|
||||
No platform is specified, assuming only a single file for a given version.
|
||||
Assuming only a single file for a given version.
|
||||
"""
|
||||
return extension_version_platform_download(request, type_slug, slug, version, None, filename)
|
||||
extension_version = get_object_or_404(Version, extension__slug=slug, version=version)
|
||||
file = extension_version.files.first()
|
||||
return file_download(request, file.hash, filename)
|
||||
|
||||
|
||||
def extension_version_platform_download(request, type_slug, slug, version, platform, filename):
|
||||
def file_download(request, filehash, filename):
|
||||
"""Download an extension version and count downloads.
|
||||
|
||||
This method processes urls constructed by Version.get_download_list.
|
||||
@ -70,13 +70,13 @@ def extension_version_platform_download(request, type_slug, slug, version, platf
|
||||
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)
|
||||
# TODO check file status
|
||||
file = get_object_or_404(File, hash=filehash, version__isnull=False)
|
||||
extension_version = file.version.first()
|
||||
ExtensionDownload.create_from_request(request, object_id=extension_version.extension_id)
|
||||
VersionDownload.create_from_request(request, object_id=extension_version.pk)
|
||||
if file := extension_version.get_file_for_platform(platform):
|
||||
url = file.source.url
|
||||
return redirect(f'{url}?filename={filename}')
|
||||
raise Http404()
|
||||
url = file.source.url
|
||||
return redirect(f'{url}?filename={filename}')
|
||||
|
||||
|
||||
class SearchView(ListedExtensionsView):
|
||||
|
@ -82,7 +82,7 @@ class TestTasks(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = self.client.get(version.extension.get_versions_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = self.client.get(version.get_download_url())
|
||||
response = self.client.get(version.get_download_url(version.files.first()))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(
|
||||
response['Location'],
|
||||
|
Loading…
Reference in New Issue
Block a user
Would it make sense to use file hash in the URL?
This would allow skipping the file-selecting logic in the
public
view altogether by using the hash to retrieve the file directly.