diff --git a/mfr/extensions/jasp/render.py b/mfr/extensions/jasp/render.py index ffcc8a76d..abcece4b4 100644 --- a/mfr/extensions/jasp/render.py +++ b/mfr/extensions/jasp/render.py @@ -1,3 +1,4 @@ +import json import os from mako.lookup import TemplateLookup @@ -67,16 +68,30 @@ def _check_file(self, zip_file): """ # Extract manifest file content try: - with zip_file.open('META-INF/MANIFEST.MF') as manifest_data: - manifest = manifest_data.read().decode('utf-8') + try: + # new manifest location + with zip_file.open('manifest.json') as manifest_data: + manifest, flavor = manifest_data.read().decode('utf-8'), 'json' + except KeyError: + # old manifest location + with zip_file.open('META-INF/MANIFEST.MF') as manifest_data: + manifest, flavor = manifest_data.read().decode('utf-8'), 'java' except KeyError: raise exceptions.JaspFileCorruptError( - '{} Missing META-INF/MANIFEST.MF'.format(self.MESSAGE_FILE_CORRUPT), + '{} Missing manifest'.format(self.MESSAGE_FILE_CORRUPT), extension=self.metadata.ext, corruption_type='key_error', - reason='zip missing ./META-INF/MANIFEST.MF', + reason='zip missing manifest', ) + if flavor == 'java': + self._verify_java_manifest(manifest) + else: + self._verify_json_manifest(manifest) + + return True + + def _verify_java_manifest(self, manifest): lines = manifest.split('\n') # Search for Data-Archive-Version @@ -121,4 +136,41 @@ def _check_file(self, zip_file): reason='Data-Archive-Version ({}) not parsable.'.format(dataArchiveVersionStr), ) - return True + return + + def _verify_json_manifest(self, manifest): + + manifest_data = json.loads(manifest) + + jasp_archive_version_str = manifest_data.get('jaspArchiveVersion', None) + if not jasp_archive_version_str: + raise exceptions.JaspFileCorruptError( + '{} jaspArchiveVersion not found.'.format(self.MESSAGE_FILE_CORRUPT), + extension=self.metadata.ext, + corruption_type='manifest_parse_error', + reason='jaspArchiveVersion not found.', + ) + + # Check that the file is new enough (contains preview content) + jasp_archive_version = LooseVersion(jasp_archive_version_str) + try: + if jasp_archive_version < self.MINIMUM_VERSION: + minimum_version = self.MINIMUM_VERSION.vstring + data_archive_version = jasp_archive_version.vstring + raise exceptions.JaspVersionError( + 'This JASP file was created with an older data archive ' + 'version ({}) and cannot be previewed. Minimum data archive ' + 'version is {}.'.format(data_archive_version, minimum_version), + extension=self.metadata.ext, + actual_version=data_archive_version, + required_version=minimum_version, + ) + except TypeError: + raise exceptions.JaspFileCorruptError( + '{} jaspArchiveVersion not parsable.'.format(self.MESSAGE_FILE_CORRUPT), + extension=self.metadata.ext, + corruption_type='manifest_parse_error', + reason='jaspArchiveVersion ({}) not parsable.'.format(jasp_archive_version_str), + ) + + return diff --git a/tests/extensions/jasp/files/ok-new-manifest.jasp b/tests/extensions/jasp/files/ok-new-manifest.jasp new file mode 100644 index 000000000..6d24f21af Binary files /dev/null and b/tests/extensions/jasp/files/ok-new-manifest.jasp differ diff --git a/tests/extensions/jasp/files/ok.jasp b/tests/extensions/jasp/files/ok-old-manifest.jasp similarity index 100% rename from tests/extensions/jasp/files/ok.jasp rename to tests/extensions/jasp/files/ok-old-manifest.jasp diff --git a/tests/extensions/jasp/test_renderer.py b/tests/extensions/jasp/test_renderer.py index 6a287f63f..b168487a6 100644 --- a/tests/extensions/jasp/test_renderer.py +++ b/tests/extensions/jasp/test_renderer.py @@ -11,8 +11,12 @@ def metadata(): return ProviderMetadata('JASP', '.jasp', 'application/octet-stream', '1234', 'http://wb.osf.io/file/JASP.jasp?token=1234') @pytest.fixture -def ok_path(): - return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'ok.jasp') +def ok_old_manifest_path(): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'ok-old-manifest.jasp') + +@pytest.fixture +def ok_new_manifest_path(): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'ok-new-manifest.jasp') @pytest.fixture def not_a_zip_file_path(): @@ -60,8 +64,8 @@ def extension(): @pytest.fixture -def renderer(metadata, ok_path, url, assets_url, export_url): - return JASPRenderer(metadata, ok_path, url, assets_url, export_url) +def renderer(metadata, ok_new_manifest_path, url, assets_url, export_url): + return JASPRenderer(metadata, ok_new_manifest_path, url, assets_url, export_url) class TestCodeJASPRenderer: @@ -70,6 +74,11 @@ def test_render_JASP(self, renderer): body = renderer.render() assert '
' in body + def test_render_JASP_old_manifest(self, metadata, ok_old_manifest_path, url, assets_url, export_url): + renderer = JASPRenderer(metadata, ok_old_manifest_path, url, assets_url, export_url) + body = renderer.render() + assert '
' in body + def test_render_JASP_not_a_zip_file(self, metadata, not_a_zip_file_path, url, assets_url, export_url): try: renderer = JASPRenderer(metadata, not_a_zip_file_path, url, assets_url, export_url)