phase 1 backup - support for multi-file versioned upload
This commit is contained in:
+97
-13
@@ -20,6 +20,7 @@ from .models import (
|
||||
TagList,
|
||||
TempUpload,
|
||||
Version,
|
||||
VersionFile,
|
||||
)
|
||||
|
||||
|
||||
@@ -113,7 +114,7 @@ class UGCProjectTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertEqual(project.versions.count(), 1)
|
||||
self.assertIsNotNone(project.thumbnail)
|
||||
self.assertTrue(project.thumbnail.stored_path.startswith('project_'))
|
||||
self.assertTrue(project.versions.first().file.stored_path.startswith('project_'))
|
||||
self.assertTrue(project.versions.first().files.first().file.stored_path.startswith('project_'))
|
||||
# Temp uploads marked used.
|
||||
self.assertEqual(
|
||||
TempUpload.objects.filter(user=self.alice, status='used').count(), 2
|
||||
@@ -138,23 +139,31 @@ class UGCProjectTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertFalse(Project.objects.filter(slug='no-file').exists())
|
||||
|
||||
def test_create_adopts_media_and_caption(self):
|
||||
def test_create_adopts_media_and_captions(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self._upload_temp('thumbnail', 'thumb.png', make_png_bytes(), 'image/png')
|
||||
self._upload_temp('version', 'pack.zip', make_zip_bytes(), 'application/zip')
|
||||
self._upload_temp('media', 'pic1.png', make_png_bytes(), 'image/png')
|
||||
self._upload_temp('media', 'pic2.png', make_png_bytes(), 'image/png')
|
||||
media = TempUpload.objects.filter(kind='media').order_by('created_at')
|
||||
caption_payload = {
|
||||
f'caption_{media[0].uuid}': 'Showcase',
|
||||
f'caption_{media[1].uuid}': 'Second angle',
|
||||
}
|
||||
resp = self.client.post(reverse('library:project_create'), {
|
||||
'title': 'Media Pack',
|
||||
'category': 'skin',
|
||||
'version_name': '1.0.0',
|
||||
'caption': 'Showcase',
|
||||
**caption_payload,
|
||||
})
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['media-pack']))
|
||||
project = Project.objects.get(slug='media-pack')
|
||||
self.assertEqual(project.assets.count(), 2)
|
||||
self.assertEqual(project.assets.first().caption, 'Showcase')
|
||||
# Per-file captions stored individually.
|
||||
captions = dict(project.assets.values_list('file__original_filename', 'caption'))
|
||||
self.assertEqual(captions['pic1.png'], 'Showcase')
|
||||
self.assertEqual(captions['pic2.png'], 'Second angle')
|
||||
for asset in project.assets.all():
|
||||
self.assertTrue(asset.file.stored_path.startswith('project_'))
|
||||
|
||||
@@ -207,13 +216,39 @@ class UGCVersionTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertEqual(self.project.versions.count(), 1)
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.version_name, '2.0.0')
|
||||
self.assertTrue(version.file_id)
|
||||
self.assertEqual(version.files.count(), 1)
|
||||
# Adopted file moved under project_<pk>/versions/ and temp marked used.
|
||||
self.assertTrue(version.file.stored_path.startswith('project_'))
|
||||
self.assertTrue(version.files.first().file.stored_path.startswith('project_'))
|
||||
self.assertTrue(
|
||||
TempUpload.objects.filter(user=self.alice, kind='version', status='used').exists()
|
||||
)
|
||||
|
||||
def test_upload_version_multiple_files(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
for name in ('skin1.png', 'skin2.png'):
|
||||
self.client.post(
|
||||
reverse('library:api_upload_temp'),
|
||||
{'kind': 'version', 'file': SimpleUploadedFile(name, make_png_bytes(), content_type='image/png')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
resp = self.client.post(
|
||||
reverse('library:version_upload', args=['test-pack']),
|
||||
{'version_name': '3.0.0'},
|
||||
)
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['test-pack']))
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.version_name, '3.0.0')
|
||||
# One version, several files, PNGs classified as png kind.
|
||||
self.assertEqual(version.files.count(), 2)
|
||||
self.assertEqual(
|
||||
set(version.files.values_list('kind', flat=True)), {'png'}
|
||||
)
|
||||
self.assertEqual(
|
||||
set(version.files.values_list('file__original_filename', flat=True)),
|
||||
{'skin1.png', 'skin2.png'},
|
||||
)
|
||||
|
||||
def test_upload_version_requires_pending_file(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
@@ -259,7 +294,8 @@ class UGCVersionTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
SimpleUploadedFile('pack.zip', make_zip_bytes(), content_type='application/zip'),
|
||||
self.project.pk, subdir='versions',
|
||||
)
|
||||
version = Version.objects.create(project=self.project, version_name='1.0.0', file=index)
|
||||
version = Version.objects.create(project=self.project, version_name='1.0.0')
|
||||
VersionFile.objects.create(version=version, file=index, kind='release')
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:version_download', args=['test-pack', version.pk]))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
@@ -270,6 +306,29 @@ class UGCVersionTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(b''.join(resp.streaming_content), make_zip_bytes())
|
||||
|
||||
def test_per_file_download(self):
|
||||
from library.storage import store_file
|
||||
|
||||
index = store_file(
|
||||
self.alice, 'version',
|
||||
SimpleUploadedFile('pack.zip', make_zip_bytes(), content_type='application/zip'),
|
||||
self.project.pk, subdir='versions',
|
||||
)
|
||||
version = Version.objects.create(project=self.project, version_name='1.0.0')
|
||||
vf = VersionFile.objects.create(version=version, file=index, kind='release')
|
||||
self.gate()
|
||||
resp = self.client.get(
|
||||
reverse('library:version_file_download', args=['test-pack', version.pk, index.uuid])
|
||||
)
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
version.refresh_from_db()
|
||||
self.assertEqual(version.downloads, 1)
|
||||
self.assertEqual(resp.url, reverse('library:file_request', args=[index.uuid]) + '?download=1')
|
||||
# The parent version_download route still works (first file).
|
||||
resp = self.client.get(reverse('library:version_download', args=['test-pack', version.pk]))
|
||||
self.assertEqual(resp.status_code, 302)
|
||||
self.assertTrue(vf)
|
||||
|
||||
|
||||
class UGCGalleryTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
def setUp(self):
|
||||
@@ -282,7 +341,7 @@ class UGCGalleryTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
slug='test-pack', title='Test Pack', category='skin', owner=self.alice,
|
||||
)
|
||||
|
||||
def test_upload_image_asset(self):
|
||||
def test_upload_image_asset_with_caption(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self.client.post(
|
||||
@@ -290,13 +349,38 @@ class UGCGalleryTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
{'kind': 'media', 'file': SimpleUploadedFile('pic.png', make_png_bytes(), content_type='image/png')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
resp = self.client.post(reverse('library:asset_upload', args=['test-pack']), {'caption': 'Preview'})
|
||||
temp = TempUpload.objects.get(kind='media')
|
||||
resp = self.client.post(
|
||||
reverse('library:asset_upload', args=['test-pack']),
|
||||
{f'caption_{temp.uuid}': 'Preview'},
|
||||
)
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['test-pack']))
|
||||
asset = ProjectAsset.objects.get()
|
||||
self.assertEqual(asset.caption, 'Preview')
|
||||
self.assertEqual(asset.uploaded_by, self.alice)
|
||||
self.assertFalse(asset.is_video)
|
||||
|
||||
def test_asset_captions_are_per_file(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self.client.post(
|
||||
reverse('library:api_upload_temp'),
|
||||
{'kind': 'media', 'file': SimpleUploadedFile('a.png', make_png_bytes(color='red'), content_type='image/png')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
self.client.post(
|
||||
reverse('library:api_upload_temp'),
|
||||
{'kind': 'media', 'file': SimpleUploadedFile('b.png', make_png_bytes(color='blue'), content_type='image/png')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
temps = list(TempUpload.objects.filter(kind='media').order_by('created_at'))
|
||||
self.client.post(reverse('library:asset_upload', args=['test-pack']), {
|
||||
f'caption_{temps[0].uuid}': 'First',
|
||||
f'caption_{temps[1].uuid}': 'Second',
|
||||
})
|
||||
captions = dict(ProjectAsset.objects.values_list('file__original_filename', 'caption'))
|
||||
self.assertEqual(captions, {'a.png': 'First', 'b.png': 'Second'})
|
||||
|
||||
def test_reject_non_media_file(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
@@ -311,7 +395,7 @@ class UGCGalleryTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
def test_gallery_upload_requires_pending_media(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.post(reverse('library:asset_upload', args=['test-pack']), {'caption': 'none'})
|
||||
resp = self.client.post(reverse('library:asset_upload', args=['test-pack']))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(ProjectAsset.objects.count(), 0)
|
||||
|
||||
@@ -427,7 +511,7 @@ class UGCDraftTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
self.assertEqual(TempUpload.objects.count(), 0)
|
||||
|
||||
def test_thumbnail_and_version_are_single_slot(self):
|
||||
def test_thumbnail_single_slot_version_multi(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self.client.post(
|
||||
@@ -450,12 +534,12 @@ class UGCDraftTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
{'kind': 'version', 'file': SimpleUploadedFile('v2.zip', make_zip_bytes(), content_type='application/zip')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
# Only the latest thumbnail + version remain; media unaffected.
|
||||
# Thumbnail is a single slot; version accepts multiple files.
|
||||
self.assertEqual(
|
||||
TempUpload.objects.filter(kind='thumbnail', status='pending').count(), 1
|
||||
)
|
||||
self.assertEqual(
|
||||
TempUpload.objects.filter(kind='version', status='pending').count(), 1
|
||||
TempUpload.objects.filter(kind='version', status='pending').count(), 2
|
||||
)
|
||||
|
||||
def test_temp_upload_delete(self):
|
||||
|
||||
Reference in New Issue
Block a user