diff --git a/qgis-app/plugins/tests/test_validator.py b/qgis-app/plugins/tests/test_validator.py index 62414a9a..7a0e7e4e 100644 --- a/qgis-app/plugins/tests/test_validator.py +++ b/qgis-app/plugins/tests/test_validator.py @@ -233,4 +233,50 @@ def test_plugin_without_license(self): charset="utf8", ) ) - ) \ No newline at end of file + ) + +class TestMultipleParentFoldersValidator(TestCase): + """Test if zipfile contains multiple parent folders """ + + def setUp(self) -> None: + multi_parents_plugin = os.path.join(TESTFILE_DIR, "multi_parents_plugin.zip_") + self.multi_parents_plugin_package = open(multi_parents_plugin, "rb") + valid_plugin = os.path.join(TESTFILE_DIR, "valid_plugin.zip_") + self.single_parent_plugin_package = open(valid_plugin, "rb") + + def tearDown(self): + self.multi_parents_plugin_package.close() + self.single_parent_plugin_package.close() + + def _get_value_by_attribute(self, attribute, data): + for key, value in data: + if key == attribute: + return value + return None + def test_plugin_with_multiple_parents(self): + result = validator( + InMemoryUploadedFile( + self.multi_parents_plugin_package, + field_name="tempfile", + name="testfile.zip", + content_type="application/zip", + size=39889, + charset="utf8", + ) + ) + multiple_parent_folders = self._get_value_by_attribute('multiple_parent_folders', result) + self.assertIsNotNone(multiple_parent_folders) + + def test_plugin_with_single_parent(self): + result = validator( + InMemoryUploadedFile( + self.single_parent_plugin_package, + field_name="tempfile", + name="testfile.zip", + content_type="application/zip", + size=39889, + charset="utf8", + ) + ) + multiple_parent_folders = self._get_value_by_attribute('multiple_parent_folders', result) + self.assertIsNone(multiple_parent_folders) diff --git a/qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ b/qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ new file mode 100644 index 00000000..ace51b2c Binary files /dev/null and b/qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ differ diff --git a/qgis-app/plugins/validator.py b/qgis-app/plugins/validator.py index 0e7c0d31..e1482bd4 100644 --- a/qgis-app/plugins/validator.py +++ b/qgis-app/plugins/validator.py @@ -210,8 +210,20 @@ def validator(package): errors="replace", ) - # Checks that package_name exists + # Metadata list, also usefull to pass warnings to the main view + metadata = [] + namelist = zip.namelist() + # Check if the zip file contains multiple parent folders + # If it is, show a warning for now + try: + parent_folders = list(set([str(name).split('/')[0] for name in namelist])) + if len(parent_folders) > 1: + metadata.append(("multiple_parent_folders", ', '.join(parent_folders))) + except: + pass + + # Checks that package_name exists try: package_name = namelist[0][: namelist[0].index("/")] except: @@ -238,8 +250,6 @@ def validator(package): if initname not in namelist: raise ValidationError(_("Cannot find __init__.py in plugin package.")) - # Checks metadata - metadata = [] # First parse metadata.txt if metadataname in namelist: try: diff --git a/qgis-app/plugins/views.py b/qgis-app/plugins/views.py index 4a0e0bf0..52b285d6 100644 --- a/qgis-app/plugins/views.py +++ b/qgis-app/plugins/views.py @@ -478,6 +478,17 @@ def plugin_upload(request): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e: connection.close() messages.error(request, e, fail_silently=True) @@ -977,6 +988,17 @@ def version_create(request, package_name): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + _main_plugin_update(request, new_object.plugin, form) _check_optional_metadata(form, request) return HttpResponseRedirect(new_object.plugin.get_absolute_url()) @@ -1033,6 +1055,17 @@ def version_update(request, package_name, version): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e: messages.error(request, e, fail_silently=True) connection.close()