temporal upload. parcial Phase 2 implementation
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
@@ -964,3 +967,178 @@ class UGCApiTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
resp = self.client.get(reverse('library:api_users_autocomplete'), {'q': 'Ali'})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertJSONEqual(resp.content, [{'username': 'Alice'}])
|
||||
|
||||
|
||||
def _zip_bytes(entries):
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, 'w') as zf:
|
||||
for name, content in entries.items():
|
||||
zf.writestr(name, content)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def _pack_zip():
|
||||
return _zip_bytes({
|
||||
'pack.mcmeta': json.dumps({
|
||||
'pack': {'pack_format': 64, 'description': 'A test pack'},
|
||||
'animationframework': {'id': 'jakebreath:test'},
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
class UGCZipParsingTests(TestCase):
|
||||
def _write_zip(self, data, suffix='.zip'):
|
||||
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as f:
|
||||
f.write(data)
|
||||
return f.name
|
||||
|
||||
def test_read_pack_mcmeta(self):
|
||||
from library.zips import read_pack_mcmeta
|
||||
path = self._write_zip(_pack_zip())
|
||||
try:
|
||||
fmt, desc = read_pack_mcmeta(path)
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertEqual(fmt, 64)
|
||||
self.assertEqual(desc, 'A test pack')
|
||||
|
||||
def test_read_pack_mcmeta_missing(self):
|
||||
from library.zips import read_pack_mcmeta
|
||||
path = self._write_zip(_zip_bytes({'assets/x.txt': 'x'}))
|
||||
try:
|
||||
fmt, desc = read_pack_mcmeta(path)
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertIsNone(fmt)
|
||||
self.assertEqual(desc, '')
|
||||
|
||||
def test_parse_mods_folder(self):
|
||||
from library.zips import parse_mods_manifest
|
||||
path = self._write_zip(_zip_bytes({
|
||||
'minecraft/mods/a.jar': 'x', 'minecraft/mods/b.jar': 'y',
|
||||
'pack.mcmeta': '{}',
|
||||
}))
|
||||
try:
|
||||
manifest = parse_mods_manifest(path, 'pack.zip')
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertEqual(manifest['source'], 'folder')
|
||||
self.assertEqual([m['name'] for m in manifest['files']], ['a.jar', 'b.jar'])
|
||||
|
||||
def test_parse_mods_mrpack(self):
|
||||
from library.zips import parse_mods_manifest
|
||||
path = self._write_zip(_zip_bytes({
|
||||
'modrinth.index.json': json.dumps({
|
||||
'dependencies': [
|
||||
{'project_id': 'abc', 'file_name': 'mod-a.jar', 'dependency_type': 'required'},
|
||||
],
|
||||
}),
|
||||
}), suffix='.mrpack')
|
||||
try:
|
||||
manifest = parse_mods_manifest(path, 'pack.mrpack')
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertEqual(manifest['source'], 'modrinth')
|
||||
self.assertEqual(manifest['files'][0]['name'], 'mod-a.jar')
|
||||
|
||||
def test_parse_mods_curseforge(self):
|
||||
from library.zips import parse_mods_manifest
|
||||
path = self._write_zip(_zip_bytes({
|
||||
'manifest.json': json.dumps({
|
||||
'files': [{'projectID': 123, 'fileID': 456, 'fileName': 'cool-mod.jar'}],
|
||||
}),
|
||||
}))
|
||||
try:
|
||||
manifest = parse_mods_manifest(path, 'pack.zip')
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertEqual(manifest['source'], 'curseforge')
|
||||
self.assertEqual(manifest['files'][0]['name'], 'cool-mod.jar')
|
||||
|
||||
|
||||
class UGCCategoryTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.alice = User.objects.create_user(username='Alice', password='pw')
|
||||
UserProfile.objects.get_or_create(user=self.alice)
|
||||
|
||||
def _upload_version(self, name, content, content_type='application/zip'):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.post(
|
||||
reverse('library:api_upload_temp'),
|
||||
{'kind': 'version', 'file': SimpleUploadedFile(name, content, content_type=content_type)},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def _upload_version_form(self, version_name='1.0.0'):
|
||||
resp = self.client.post(
|
||||
reverse('library:version_upload', args=[self.project.slug]),
|
||||
{'version_name': version_name},
|
||||
)
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=[self.project.slug]))
|
||||
|
||||
def test_non_pack_captures_pack_mcmeta(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='non-pack', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('pack.zip', _pack_zip())
|
||||
self._upload_version_form()
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.pack_format, 64)
|
||||
self.assertEqual(version.pack_description, 'A test pack')
|
||||
|
||||
def test_modpack_captures_mods_manifest(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='modpack', title='Modpack', category='modpack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('pack.zip', _zip_bytes({'minecraft/mods/a.jar': 'x'}))
|
||||
self._upload_version_form()
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.mods_manifest['source'], 'folder')
|
||||
self.assertEqual(version.mods_manifest['files'][0]['name'], 'a.jar')
|
||||
|
||||
def test_guide_uploads_md_and_zip_and_renders(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='guide', title='Guide', category='guide', owner=self.alice,
|
||||
)
|
||||
self._upload_version('README.md', b'# Title\n\nBody text.', content_type='text/markdown')
|
||||
self._upload_version('assets.zip', _zip_bytes({'data/x.json': '{}'}))
|
||||
self._upload_version_form()
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(
|
||||
set(version.files.values_list('kind', flat=True)), {'markdown', 'release'}
|
||||
)
|
||||
md_vf = version.files.get(kind='markdown')
|
||||
# guide_doc endpoint renders the markdown server-side.
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:guide_doc', args=['guide', version.pk, md_vf.file.uuid]))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertContains(resp, '<h1>Title</h1>', html=True)
|
||||
# Detail page exposes the guide switcher.
|
||||
resp = self.client.get(reverse('library:project_detail', args=['guide']))
|
||||
self.assertContains(resp, 'guide-switcher')
|
||||
self.assertContains(resp, 'README.md')
|
||||
|
||||
def test_guide_doc_rejects_non_markdown(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='guide', title='Guide', category='guide', owner=self.alice,
|
||||
)
|
||||
self._upload_version('pack.zip', _zip_bytes({'data/x.json': '{}'}))
|
||||
self._upload_version_form()
|
||||
version = self.project.versions.first()
|
||||
vf = version.files.get(kind='release')
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:guide_doc', args=['guide', version.pk, vf.file.uuid]))
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_regular_category_has_no_extra_metadata(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='mod', title='Mod', category='mod', owner=self.alice,
|
||||
)
|
||||
self._upload_version('pack.zip', _pack_zip())
|
||||
self._upload_version_form()
|
||||
version = self.project.versions.first()
|
||||
self.assertIsNone(version.pack_format)
|
||||
self.assertEqual(version.mods_manifest, {})
|
||||
|
||||
Reference in New Issue
Block a user