diff --git a/qgis-app/plugins/forms.py b/qgis-app/plugins/forms.py index 99dc804a..600986de 100644 --- a/qgis-app/plugins/forms.py +++ b/qgis-app/plugins/forms.py @@ -132,7 +132,8 @@ def clean(self): self.cleaned_data.get("version") ) self.instance.server = self.cleaned_data.get("server") - # Check plugin name + + # Check plugin folder name if ( self.cleaned_data.get("package_name") and self.cleaned_data.get("package_name") @@ -140,7 +141,7 @@ def clean(self): ): raise ValidationError( _( - "Plugin name mismatch: the plugin main folder name in the compressed file (%s) is different from the original plugin package name (%s)." + "Plugin folder name mismatch: the plugin main folder name in the compressed file (%s) is different from the original plugin package name (%s)." ) % ( self.cleaned_data.get("package_name"), diff --git a/qgis-app/plugins/migrations/0003_plugin_allow_update_name.py b/qgis-app/plugins/migrations/0003_plugin_allow_update_name.py new file mode 100644 index 00000000..dac62f7f --- /dev/null +++ b/qgis-app/plugins/migrations/0003_plugin_allow_update_name.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.25 on 2023-11-07 03:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('plugins', '0002_pluginversiondownload'), + ] + + operations = [ + migrations.AddField( + model_name='plugin', + name='allow_update_name', + field=models.BooleanField(default=False, help_text='Allow name in metadata.txt to update the plugin name', verbose_name='Allow update name'), + ), + ] diff --git a/qgis-app/plugins/models.py b/qgis-app/plugins/models.py index 7deee802..eeba37d2 100644 --- a/qgis-app/plugins/models.py +++ b/qgis-app/plugins/models.py @@ -350,6 +350,13 @@ class Plugin(models.Model): name = models.CharField( _("Name"), help_text=_("Must be unique"), max_length=256, unique=True ) + + allow_update_name = models.BooleanField( + _("Allow update name"), + help_text=_("Allow name in metadata.txt to update the plugin name"), + default=False + ) + description = models.TextField(_("Description")) about = models.TextField(_("About"), blank=False, null=True) diff --git a/qgis-app/plugins/tests/test_rename_plugin.py b/qgis-app/plugins/tests/test_rename_plugin.py new file mode 100644 index 00000000..d1eb890b --- /dev/null +++ b/qgis-app/plugins/tests/test_rename_plugin.py @@ -0,0 +1,111 @@ +import os +from unittest.mock import patch + +from django.urls import reverse +from django.test import Client, TestCase, override_settings +from django.contrib.auth.models import User +from django.core.files.uploadedfile import SimpleUploadedFile +from plugins.models import Plugin, PluginVersion +from plugins.forms import PluginVersionForm + +def do_nothing(*args, **kwargs): + pass + +TESTFILE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "testfiles")) + +class PluginRenameTestCase(TestCase): + fixtures = [ + "fixtures/styles.json", + "fixtures/auth.json", + "fixtures/simplemenu.json", + ] + + @override_settings(MEDIA_ROOT="api/tests") + def setUp(self): + self.client = Client() + self.url_upload = reverse('plugin_upload') + + # Create a test user + self.user = User.objects.create_user( + username='testuser', + password='testpassword', + email='test@example.com' + ) + + # Log in the test user + self.client.login(username='testuser', password='testpassword') + + # Upload a plugin for renaming test. + # This process is already tested in test_plugin_upload + valid_plugin = os.path.join(TESTFILE_DIR, "valid_plugin.zip_") + with open(valid_plugin, "rb") as file: + uploaded_file = SimpleUploadedFile( + "valid_plugin.zip_", file.read(), + content_type="application/zip") + + self.client.post(self.url_upload, { + 'package': uploaded_file, + }) + + self.plugin = Plugin.objects.get(name='Test Plugin') + self.plugin.name = "New name Test Plugin" + self.plugin.save() + + @patch("plugins.tasks.generate_plugins_xml.delay", new=do_nothing) + @patch("plugins.validator._check_url_link", new=do_nothing) + def test_plugin_rename(self): + """ + Test rename from a new plugin version + """ + package_name = self.plugin.package_name + self.url_add_version = reverse('version_create', args=[package_name]) + # Test GET request + response = self.client.get(self.url_add_version) + self.assertEqual(response.status_code, 200) + self.assertIsInstance(response.context['form'], PluginVersionForm) + + # Test POST request with invalid form data + response = self.client.post(self.url_add_version, {}) + self.assertEqual(response.status_code, 200) + self.assertFalse(response.context['form'].is_valid()) + + # Test POST request without allowing name from metadata + valid_plugin = os.path.join(TESTFILE_DIR, "valid_plugin_0.0.2.zip_") + with open(valid_plugin, "rb") as file: + uploaded_file = SimpleUploadedFile( + "valid_plugin_0.0.2.zip_", file.read(), + content_type="application/zip_") + + response = self.client.post(self.url_add_version, { + 'package': uploaded_file, + 'experimental': False, + 'changelog': '' + }) + self.assertEqual(response.status_code, 302) + self.assertTrue(PluginVersion.objects.filter( + plugin__name='New name Test Plugin', + version='0.0.2').exists() + ) + + # Test POST request with allowing name from metadata + self.plugin.allow_update_name = True + self.plugin.save() + + valid_plugin = os.path.join(TESTFILE_DIR, "valid_plugin_0.0.3.zip_") + with open(valid_plugin, "rb") as file: + uploaded_file = SimpleUploadedFile( + "valid_plugin_0.0.3.zip_", file.read(), + content_type="application/zip_") + response = self.client.post(self.url_add_version, { + 'package': uploaded_file, + 'experimental': False, + 'changelog': '' + }) + self.assertEqual(response.status_code, 302) + self.assertTrue(PluginVersion.objects.filter( + plugin__name='Test Plugin', + version='0.0.3').exists() + ) + + def tearDown(self): + self.client.logout() diff --git a/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.2.zip_ b/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.2.zip_ new file mode 100644 index 00000000..c694809e Binary files /dev/null and b/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.2.zip_ differ diff --git a/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.3.zip_ b/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.3.zip_ new file mode 100644 index 00000000..f838d489 Binary files /dev/null and b/qgis-app/plugins/tests/testfiles/valid_plugin_0.0.3.zip_ differ diff --git a/qgis-app/plugins/views.py b/qgis-app/plugins/views.py index a8939822..3e753ac6 100644 --- a/qgis-app/plugins/views.py +++ b/qgis-app/plugins/views.py @@ -879,8 +879,13 @@ def _main_plugin_update(request, plugin, form): """ Updates the main plugin object from version metadata """ + # Check if update name from metadata is allowed + metadata_fields = ["author", "email", "description", "about", "homepage", "tracker"] + if plugin.allow_update_name: + metadata_fields.insert(0, "name") + # Update plugin from metadata - for f in ["name", "author", "email", "description", "about", "homepage", "tracker"]: + for f in metadata_fields: if form.cleaned_data.get(f): setattr(plugin, f, form.cleaned_data.get(f))