Finished with Phase 2.6
This commit is contained in:
@@ -4,6 +4,7 @@ import os
|
||||
import secrets
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
import zipfile
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
@@ -1320,3 +1321,256 @@ class UGCAnimationTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.get(reverse('library:api_packs_latest', args=['jakebreath', 'testpack']))
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
|
||||
def _geo_model_zip():
|
||||
geo = {
|
||||
'format_version': '1.12.0',
|
||||
'afw_bone_textures': {'body': 'needsofnature:textures/entity/zombie/zombie.png'},
|
||||
'minecraft:geometry': [{
|
||||
'description': {'identifier': 'geometry.unknown', 'texture_width': 64, 'texture_height': 64},
|
||||
'bones': [
|
||||
{'name': 'root', 'pivot': [0, 0, 0]},
|
||||
{'name': 'body', 'pivot': [0, 12, 0], 'cubes': [
|
||||
{'origin': [-4, 0, -4], 'size': [8, 8, 8], 'uv': [0, 0]},
|
||||
]},
|
||||
],
|
||||
}],
|
||||
}
|
||||
return _zip_bytes({
|
||||
'pack.mcmeta': json.dumps({
|
||||
'pack': {'pack_format': 88},
|
||||
'animationframework': {'id': 'christmaspuffin:models_and_textures', 'name': 'Models',
|
||||
'author': 'CP', 'version': '1.0'},
|
||||
}),
|
||||
'assets/animationframework/geckolib/models/entity/zombie.m.geo.json': json.dumps(geo),
|
||||
'assets/needsofnature/textures/entity/zombie/zombie.png': b'PNG-DATA',
|
||||
})
|
||||
|
||||
|
||||
def _logical_zip():
|
||||
return _zip_bytes({
|
||||
'pack.mcmeta': json.dumps({'pack': {'pack_format': 61}}),
|
||||
'assets/usefulcum/items/potion_gender.json': json.dumps(
|
||||
{'model': {'type': 'minecraft:model', 'model': 'usefulcum:item/potion_gender'}}),
|
||||
'assets/usefulcum/textures/item/potion_gender.png': b'PNG',
|
||||
'data/usefulcum/recipe/cum_combination.json': json.dumps({
|
||||
'type': 'minecraft:crafting_shapeless',
|
||||
'ingredients': ['minecraft:potion', 'minecraft:potion'],
|
||||
'result': {'id': 'minecraft:glass_bottle', 'count': 2},
|
||||
}),
|
||||
'data/usefulcum/advancement/recipe/blaze_cum.json': json.dumps(
|
||||
{'rewards': {'function': 'usefulcum:recipe/blaze_cum'}}),
|
||||
'data/usefulcum/advancement/change_gender.json': json.dumps(
|
||||
{'rewards': {'function': 'usefulcum:change_gender'}}),
|
||||
'data/usefulcum/function/change_gender.mcfunction': b'# x',
|
||||
'data/usefulcum/function/tick.mcfunction': b'# y',
|
||||
})
|
||||
|
||||
|
||||
class UGCContentTabsTests(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 _write_zip(self, data):
|
||||
with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f:
|
||||
f.write(data)
|
||||
return f.name
|
||||
|
||||
def _upload_version(self, slug, name, content):
|
||||
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='application/zip')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
return self.client.post(
|
||||
reverse('library:version_upload', args=[slug]), {'version_name': '1.0.0'},
|
||||
)
|
||||
|
||||
def test_read_pack_meta_without_animdefs(self):
|
||||
from library.zips import read_pack_meta
|
||||
path = self._write_zip(_geo_model_zip())
|
||||
try:
|
||||
meta = read_pack_meta(path)
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertEqual(meta['animation_id'], 'christmaspuffin:models_and_textures')
|
||||
self.assertEqual(meta['authors'], ['CP'])
|
||||
|
||||
def test_read_models_manifest(self):
|
||||
from library.zips import read_models_manifest
|
||||
path = self._write_zip(_geo_model_zip())
|
||||
try:
|
||||
manifest = read_models_manifest(path)
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertIsNotNone(manifest)
|
||||
model = manifest['models'][0]
|
||||
self.assertEqual(model['name'], 'zombie.m.geo.json')
|
||||
self.assertEqual(model['bones'], 2)
|
||||
self.assertEqual(model['cubes'], 1)
|
||||
self.assertEqual(
|
||||
model['bone_textures']['body'],
|
||||
'assets/needsofnature/textures/entity/zombie/zombie.png',
|
||||
)
|
||||
|
||||
def test_read_logical_manifest(self):
|
||||
from library.zips import read_logical_manifest
|
||||
path = self._write_zip(_logical_zip())
|
||||
try:
|
||||
manifest = read_logical_manifest(path)
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertIsNotNone(manifest)
|
||||
self.assertEqual(manifest['items'][0]['name'], 'usefulcum:potion_gender')
|
||||
self.assertEqual(manifest['recipes'][0]['ingredients'], ['minecraft:potion'])
|
||||
self.assertEqual(manifest['recipes'][0]['result'], 'minecraft:glass_bottle x2')
|
||||
self.assertEqual(manifest['custom_recipes'][0]['name'], 'blaze_cum')
|
||||
self.assertEqual(manifest['advancements'][0]['name'], 'change_gender')
|
||||
self.assertEqual(len(manifest['functions']), 2)
|
||||
|
||||
def test_models_pack_gets_id_and_models_tab(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='models-pack', title='Models Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('models-pack', 'pack.zip', _geo_model_zip())
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.animation_id, 'christmaspuffin:models_and_textures')
|
||||
self.assertTrue(version.models_manifest)
|
||||
self.assertFalse(version.animation_manifest)
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:project_detail', args=['models-pack']))
|
||||
self.assertContains(resp, 'tab-models')
|
||||
self.assertContains(resp, 'Render')
|
||||
self.assertNotContains(resp, 'tab-animations')
|
||||
|
||||
def test_logical_pack_shows_only_logical_tab(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='logical-pack', title='Logical Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('logical-pack', 'pack.zip', _logical_zip())
|
||||
version = self.project.versions.first()
|
||||
self.assertTrue(version.logical_manifest)
|
||||
self.assertFalse(version.models_manifest)
|
||||
self.assertFalse(version.animation_manifest)
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:project_detail', args=['logical-pack']))
|
||||
self.assertContains(resp, 'tab-logical')
|
||||
self.assertNotContains(resp, 'tab-models')
|
||||
self.assertNotContains(resp, 'tab-animations')
|
||||
self.assertContains(resp, 'usefulcum:potion_gender')
|
||||
|
||||
def test_pack_asset_serves_member(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='models-pack', title='Models Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('models-pack', 'pack.zip', _geo_model_zip())
|
||||
version = self.project.versions.first()
|
||||
self.gate()
|
||||
resp = self.client.get(reverse(
|
||||
'library:pack_asset',
|
||||
args=['models-pack', version.pk, 'assets/needsofnature/textures/entity/zombie/zombie.png'],
|
||||
))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp['Content-Type'].split(';')[0], 'image/png')
|
||||
self.assertEqual(resp.content, b'PNG-DATA')
|
||||
|
||||
def test_pack_asset_rejects_unknown_member(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='models-pack', title='Models Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('models-pack', 'pack.zip', _geo_model_zip())
|
||||
version = self.project.versions.first()
|
||||
self.gate()
|
||||
resp = self.client.get(reverse(
|
||||
'library:pack_asset',
|
||||
args=['models-pack', version.pk, 'assets/nope/nothing.png'],
|
||||
))
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_gallery_video_is_muted(self):
|
||||
from library.storage import store_file
|
||||
self.project = Project.objects.create(
|
||||
slug='muted', title='Muted', category='mod', owner=self.alice,
|
||||
)
|
||||
index = store_file(
|
||||
self.alice, 'asset',
|
||||
SimpleUploadedFile('clip.webm', b'webm', content_type='video/webm'),
|
||||
self.project.pk, subdir='gallery',
|
||||
)
|
||||
ProjectAsset.objects.create(project=self.project, file=index, uploaded_by=self.alice)
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:project_detail', args=['muted']))
|
||||
self.assertContains(resp, 'muted')
|
||||
|
||||
|
||||
def make_gif_bytes():
|
||||
import PIL.Image
|
||||
|
||||
frames = [PIL.Image.new('RGB', (8, 8), c) for c in ('red', 'green')]
|
||||
buf = io.BytesIO()
|
||||
frames[0].save(buf, format='GIF', save_all=True, append_images=frames[1:], duration=100, loop=0)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
class UGCThumbnailTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
@unittest.skipUnless(shutil.which('ffmpeg'), 'ffmpeg required')
|
||||
def test_video_and_gif_thumbnails(self):
|
||||
User = get_user_model()
|
||||
alice = User.objects.create_user(username='Alice', password='pw')
|
||||
UserProfile.objects.get_or_create(user=alice)
|
||||
project = Project.objects.create(slug='media', title='Media', category='mod', owner=alice)
|
||||
from library.storage import store_file
|
||||
|
||||
gif = ProjectAsset.objects.create(
|
||||
project=project, uploaded_by=alice,
|
||||
file=store_file(
|
||||
alice, 'asset',
|
||||
SimpleUploadedFile('anim.gif', make_gif_bytes(), content_type='image/gif'),
|
||||
project.pk, subdir='gallery',
|
||||
),
|
||||
)
|
||||
png = ProjectAsset.objects.create(
|
||||
project=project, uploaded_by=alice,
|
||||
file=store_file(
|
||||
alice, 'asset',
|
||||
SimpleUploadedFile('pic.png', make_png_bytes(), content_type='image/png'),
|
||||
project.pk, subdir='gallery',
|
||||
),
|
||||
)
|
||||
self.gate()
|
||||
# Gif gets a cached JPEG thumbnail.
|
||||
resp = self.client.get(reverse('library:asset_thumbnail', args=['media', gif.pk]))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp['Content-Type'].split(';')[0], 'image/jpeg')
|
||||
self.assertGreater(len(b''.join(resp.streaming_content)), 0)
|
||||
# Cached on the second request.
|
||||
resp2 = self.client.get(reverse('library:asset_thumbnail', args=['media', gif.pk]))
|
||||
self.assertEqual(resp2.status_code, 200)
|
||||
# A plain image is not thumbnailed → 404.
|
||||
resp3 = self.client.get(reverse('library:asset_thumbnail', args=['media', png.pk]))
|
||||
self.assertEqual(resp3.status_code, 404)
|
||||
|
||||
def test_gallery_grid_uses_thumbnail_for_gif(self):
|
||||
User = get_user_model()
|
||||
alice = User.objects.create_user(username='Alice', password='pw')
|
||||
UserProfile.objects.get_or_create(user=alice)
|
||||
project = Project.objects.create(slug='media', title='Media', category='mod', owner=alice)
|
||||
from library.storage import store_file
|
||||
|
||||
ProjectAsset.objects.create(
|
||||
project=project, uploaded_by=alice,
|
||||
file=store_file(
|
||||
alice, 'asset',
|
||||
SimpleUploadedFile('anim.gif', make_gif_bytes(), content_type='image/gif'),
|
||||
project.pk, subdir='gallery',
|
||||
),
|
||||
)
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:project_detail', args=['media']))
|
||||
self.assertContains(resp, '/thumb/')
|
||||
|
||||
Reference in New Issue
Block a user