Extra validation of the uploaded ZIP #73
@ -58,7 +58,7 @@ EXTENSION_TYPE_PLURAL = {
|
||||
EXTENSION_TYPE_CHOICES.THEME: _('Themes'),
|
||||
}
|
||||
EXTENSION_SLUGS_PATH = '|'.join(EXTENSION_TYPE_SLUGS.values())
|
||||
EXTENSION_TYPES = {v: k for k, v in EXTENSION_TYPE_SLUGS_SINGULAR.items()}
|
||||
EXTENSION_SLUG_TYPES = {v: k for k, v in EXTENSION_TYPE_SLUGS_SINGULAR.items()}
|
||||
|
||||
ALLOWED_EXTENSION_MIMETYPES = ('application/zip', )
|
||||
# FIXME: this controls the initial widget rendered server-side, and server-side validation
|
||||
|
BIN
extensions/tests/files/addon-single-py-module.zip
Normal file
BIN
extensions/tests/files/addon-single-py-module.zip
Normal file
Binary file not shown.
BIN
extensions/tests/files/addon-without-init.zip
Normal file
BIN
extensions/tests/files/addon-without-init.zip
Normal file
Binary file not shown.
@ -168,7 +168,21 @@ class SubmitFileTest(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertDictEqual(
|
||||
response.context['form'].errors,
|
||||
{'source': ['A theme ZIP archive should contain a single XML file']},
|
||||
{'source': ['A theme ZIP archive should only have one XML file']},
|
||||
)
|
||||
|
||||
def test_validation_errors_no_init(self):
|
||||
self.assertEqual(Extension.objects.count(), 0)
|
||||
user = UserFactory()
|
||||
self.client.force_login(user)
|
||||
|
||||
with open(TEST_FILES_DIR / 'addon-without-init.zip', 'rb') as fp:
|
||||
response = self.client.post(self.url, {'source': fp, 'agreed_with_terms': True})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertDictEqual(
|
||||
response.context['form'].errors,
|
||||
{'source': ['An add-on directory should contain an __init__.py file']},
|
||||
)
|
||||
|
||||
def test_theme_file(self):
|
||||
@ -218,6 +232,31 @@ class SubmitFileTest(TestCase):
|
||||
self.assertEqual(response.status_code, 200, _get_all_form_errors(response))
|
||||
self.assertEqual(File.objects.count(), 0)
|
||||
|
||||
def test_addon_single_py(self):
|
||||
self.assertEqual(File.objects.count(), 0)
|
||||
user = UserFactory()
|
||||
self.client.force_login(user)
|
||||
|
||||
with open(TEST_FILES_DIR / 'addon-single-py-module.zip', 'rb') as fp:
|
||||
response = self.client.post(self.url, {'source': fp, 'agreed_with_terms': True})
|
||||
|
||||
self.assertEqual(response.status_code, 302, _get_all_form_errors(response))
|
||||
self.assertEqual(File.objects.count(), 1)
|
||||
file = File.objects.first()
|
||||
self.assertEqual(response['Location'], file.get_submit_url())
|
||||
self.assertEqual(file.user, user)
|
||||
self.assertEqual(file.original_name, 'addon-single-py-module.zip')
|
||||
self.assertEqual(file.size_bytes, 558)
|
||||
self.assertEqual(
|
||||
file.original_hash,
|
||||
'sha256:21408edc82b70a16fd332311faf297b86a29c96cea554b206a162394033c2451',
|
||||
)
|
||||
self.assertEqual(
|
||||
file.hash, 'sha256:21408edc82b70a16fd332311faf297b86a29c96cea554b206a162394033c2451',
|
||||
)
|
||||
self.assertEqual(file.get_type_display(), 'Add-on')
|
||||
self.assertEqual(file.metadata['name'], 'Some Add-on')
|
||||
|
||||
|
||||
for file_name, data in EXPECTED_EXTENSION_DATA.items():
|
||||
|
||||
|
@ -13,7 +13,7 @@ from .validators import (
|
||||
FileMIMETypeValidator,
|
||||
ManifestValidator,
|
||||
)
|
||||
from constants.base import EXTENSION_TYPES, ALLOWED_EXTENSION_MIMETYPES
|
||||
from constants.base import EXTENSION_SLUG_TYPES, ALLOWED_EXTENSION_MIMETYPES
|
||||
import files.models
|
||||
import files.utils as utils
|
||||
|
||||
@ -31,7 +31,8 @@ class FileForm(forms.ModelForm):
|
||||
error_messages = {
|
||||
'invalid_manifest_toml': _('A valid manifest file could not be found'),
|
||||
'invalid_zip_archive': msg_only_zip_files,
|
||||
'invalid_theme_multiple_xmls': _('A theme ZIP archive should contain a single XML file'),
|
||||
'invalid_theme_multiple_xmls': _('A theme ZIP archive should only have one XML file'),
|
||||
'invalid_missing_init': _('An add-on directory should contain an __init__.py file'),
|
||||
}
|
||||
|
||||
class Meta:
|
||||
@ -151,6 +152,6 @@ class FileForm(forms.ModelForm):
|
||||
|
||||
self.cleaned_data['metadata'] = manifest
|
||||
# TODO: Error handling
|
||||
self.cleaned_data['type'] = EXTENSION_TYPES[manifest['type']]
|
||||
self.cleaned_data['type'] = EXTENSION_SLUG_TYPES[manifest['type']]
|
||||
|
||||
return self.cleaned_data
|
||||
|
@ -89,11 +89,18 @@ def read_manifest_from_zip(archive_path):
|
||||
with myzip.open(manifest_filepath) as file_content:
|
||||
toml_content = toml.loads(file_content.read().decode())
|
||||
|
||||
is_a_directory = '/' in manifest_filepath
|
||||
# In case manifest TOML was successfully parsed, do additional type-specific validation
|
||||
if toml_content['type'] == 'theme':
|
||||
type_slug = toml_content['type']
|
||||
if type_slug == 'theme':
|
||||
theme_xmls = filter_file_paths_by_ext(file_list, '.xml')
|
||||
if len(list(theme_xmls)) != 1:
|
||||
error_codes.append('invalid_theme_multiple_xmls')
|
||||
elif type_slug == 'add-on':
|
||||
if is_a_directory:
|
||||
init_filepath = find_file_inside_zip_list('__init__.py', file_list)
|
||||
if not init_filepath:
|
||||
error_codes.append('invalid_missing_init')
|
||||
|
||||
return toml_content, error_codes
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user