From d27e30b2761e8927d838882255d2cc7718ae94b5 Mon Sep 17 00:00:00 2001 From: Alexander CherryTea Date: Tue, 19 Dec 2023 09:09:18 +0100 Subject: [PATCH 1/8] add matomo script and connect it with base template (#320) * add matomo script and connect it with base template * add django-matomo plugin * remove manually added script * update docker requirements * add matomo to installed apps * add matomo variables in settings for docker --- REQUIREMENTS.txt | 1 + dockerize/docker/REQUIREMENTS.txt | 1 + qgis-app/settings.py | 4 ++++ qgis-app/settings_docker.py | 4 ++++ qgis-app/templates/base.html | 4 +++- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/REQUIREMENTS.txt b/REQUIREMENTS.txt index 6e4c7f04..ab2d4e1f 100644 --- a/REQUIREMENTS.txt +++ b/REQUIREMENTS.txt @@ -59,3 +59,4 @@ django-user-map djangorestframework==3.12.2 django-rest-auth==0.9.5 drf-yasg +django-matomo==0.1.6 \ No newline at end of file diff --git a/dockerize/docker/REQUIREMENTS.txt b/dockerize/docker/REQUIREMENTS.txt index 901d9427..d74ab808 100644 --- a/dockerize/docker/REQUIREMENTS.txt +++ b/dockerize/docker/REQUIREMENTS.txt @@ -53,3 +53,4 @@ django-rest-multiple-models==2.1.3 django-preferences==1.0.0 PyWavefront==1.3.3 +django-matomo==0.1.6 diff --git a/qgis-app/settings.py b/qgis-app/settings.py index 54d76a4a..e79a9821 100644 --- a/qgis-app/settings.py +++ b/qgis-app/settings.py @@ -152,6 +152,7 @@ "preferences", # styles: "styles", + "matomo" ] TEMPLATES = [ @@ -329,3 +330,6 @@ RESULT_BACKEND = BROKER_URL CELERY_BROKER_URL = BROKER_URL CELERY_RESULT_BACKEND = CELERY_BROKER_URL + +MATOMO_SITE_ID="1" +MATOMO_URL="//matomo.qgis.org/" diff --git a/qgis-app/settings_docker.py b/qgis-app/settings_docker.py index afb1c9e9..25784d91 100644 --- a/qgis-app/settings_docker.py +++ b/qgis-app/settings_docker.py @@ -76,6 +76,7 @@ # models (sharing .model3 file feature) "models", "wavefronts", + "matomo" ] DATABASES = { @@ -120,3 +121,6 @@ REST_FRAMEWORK = { "TEST_REQUEST_DEFAULT_FORMAT": "json", } + +MATOMO_SITE_ID="1" +MATOMO_URL="//matomo.qgis.org/" \ No newline at end of file diff --git a/qgis-app/templates/base.html b/qgis-app/templates/base.html index 69195e7e..fdaa81a7 100644 --- a/qgis-app/templates/base.html +++ b/qgis-app/templates/base.html @@ -1,5 +1,6 @@ {% load i18n simplemenu_tags static %} {% load resources_custom_tags %} +{% load matomo_tags %} @@ -21,7 +22,7 @@ - + +{% tracking_code %} From 3b91ae7996f933bd510282196614160f5c79339a Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:15:02 +0300 Subject: [PATCH 2/8] Disable matomo cookies (#333) --- qgis-app/templates/matomo/tracking_code.html | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 qgis-app/templates/matomo/tracking_code.html diff --git a/qgis-app/templates/matomo/tracking_code.html b/qgis-app/templates/matomo/tracking_code.html new file mode 100644 index 00000000..175a75a4 --- /dev/null +++ b/qgis-app/templates/matomo/tracking_code.html @@ -0,0 +1,23 @@ + + + \ No newline at end of file From 6fe3124a7767ccafa4590d8a988771cbdbf539c6 Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:41:40 +0300 Subject: [PATCH 3/8] Fix different displayed date (#315) * Implement moment.js, fix different displayed date * Fix displayed date for Created on column --- .../templates/plugins/plugin_list.html | 5 +- .../templates/plugins/version_detail.html | 3 +- .../plugins/templatetags/local_timezone.py | 9 +- qgis-app/static/js/local_timezone.js | 27 +- qgis-app/static/js/moment.min.js | 5685 +++++++++++++++++ qgis-app/templates/base.html | 1 + 6 files changed, 5721 insertions(+), 9 deletions(-) create mode 100644 qgis-app/static/js/moment.min.js diff --git a/qgis-app/plugins/templates/plugins/plugin_list.html b/qgis-app/plugins/templates/plugins/plugin_list.html index 513a8d09..c959d4f8 100644 --- a/qgis-app/plugins/templates/plugins/plugin_list.html +++ b/qgis-app/plugins/templates/plugins/plugin_list.html @@ -1,4 +1,5 @@ {% extends 'plugins/plugin_base.html' %}{% load i18n bootstrap_pagination humanize static sort_anchor range_filter thumbnail %} +{% load local_timezone %} {% block extrajs %} + {% tracking_code %} From 5b3bdd990695b02997b560d38ce1f5b2c7e53b73 Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:49:25 +0300 Subject: [PATCH 4/8] Add maintainer field to plugin update (#316) * Add maintainer field to plugin update * Add maintainer and display_created_by fields --------- Co-authored-by: Dimas Ciputra --- qgis-app/plugins/forms.py | 15 +++ .../migrations/0005_plugin_maintainer.py | 29 +++++ .../0006_plugin_display_created_by.py | 18 ++++ qgis-app/plugins/models.py | 19 ++++ .../templates/plugins/plugin_detail.html | 9 +- .../templates/plugins/plugin_form.html | 2 +- .../plugins/tests/test_change_maintainer.py | 101 ++++++++++++++++++ 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 qgis-app/plugins/migrations/0005_plugin_maintainer.py create mode 100644 qgis-app/plugins/migrations/0006_plugin_display_created_by.py create mode 100644 qgis-app/plugins/tests/test_change_maintainer.py diff --git a/qgis-app/plugins/forms.py b/qgis-app/plugins/forms.py index 600986de..5147bacc 100644 --- a/qgis-app/plugins/forms.py +++ b/qgis-app/plugins/forms.py @@ -43,10 +43,25 @@ class Meta: "tracker", "repository", "owners", + "maintainer", + "display_created_by", "tags", "server", ) + def __init__(self, *args, **kwargs): + super(PluginForm, self).__init__(*args, **kwargs) + self.fields['owners'].label = "Collaborators" + + choices = ( + (self.instance.created_by.pk, self.instance.created_by.username + " (Plugin creator)"), + ) + for owner in self.instance.owners.exclude(pk=self.instance.created_by.pk): + choices += ((owner.pk, owner.username + " (Collaborator)"),) + + self.fields['maintainer'].choices = choices + self.fields['maintainer'].label = "Maintainer" + def clean(self): """ Check author diff --git a/qgis-app/plugins/migrations/0005_plugin_maintainer.py b/qgis-app/plugins/migrations/0005_plugin_maintainer.py new file mode 100644 index 00000000..dfeffa0b --- /dev/null +++ b/qgis-app/plugins/migrations/0005_plugin_maintainer.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.25 on 2023-11-29 22:45 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + +def populate_maintainer(apps, schema_editor): + Plugin = apps.get_model('plugins', 'Plugin') + + # Set the maintainer as the plugin creator by default + for obj in Plugin.objects.all(): + obj.maintainer = obj.created_by + obj.save() + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('plugins', '0004_merge_20231122_0223'), + ] + + operations = [ + migrations.AddField( + model_name='plugin', + name='maintainer', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='plugins_maintainer', to=settings.AUTH_USER_MODEL, verbose_name='Maintainer'), + ), + migrations.RunPython(populate_maintainer), + ] diff --git a/qgis-app/plugins/migrations/0006_plugin_display_created_by.py b/qgis-app/plugins/migrations/0006_plugin_display_created_by.py new file mode 100644 index 00000000..85af8484 --- /dev/null +++ b/qgis-app/plugins/migrations/0006_plugin_display_created_by.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.25 on 2023-11-29 23:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('plugins', '0005_plugin_maintainer'), + ] + + operations = [ + migrations.AddField( + model_name='plugin', + name='display_created_by', + field=models.BooleanField(default=False, verbose_name='Display "Created by" in plugin details'), + ), + ] diff --git a/qgis-app/plugins/models.py b/qgis-app/plugins/models.py index eeba37d2..db95fda6 100644 --- a/qgis-app/plugins/models.py +++ b/qgis-app/plugins/models.py @@ -322,6 +322,22 @@ class Plugin(models.Model): related_name="plugins_created_by", on_delete=models.CASCADE, ) + + # maintainer + maintainer = models.ForeignKey( + User, + verbose_name=_("Maintainer"), + related_name="plugins_maintainer", + on_delete=models.CASCADE, + blank=True, + null=True + ) + + display_created_by = models.BooleanField( + _('Display "Created by" in plugin details'), + default=False + ) + author = models.CharField( _("Author"), help_text=_( @@ -529,6 +545,7 @@ def save(self, keep_date=False, *args, **kwargs): """ Soft triggers: * updates modified_on if keep_date is not set + * set maintainer to the plugin creator when not specified """ if self.pk and not keep_date: import logging @@ -537,6 +554,8 @@ def save(self, keep_date=False, *args, **kwargs): self.modified_on = datetime.datetime.now() if not self.pk: self.modified_on = datetime.datetime.now() + if not self.maintainer: + self.maintainer = self.created_by super(Plugin, self).save(*args, **kwargs) diff --git a/qgis-app/plugins/templates/plugins/plugin_detail.html b/qgis-app/plugins/templates/plugins/plugin_detail.html index db7468c9..bc48879e 100644 --- a/qgis-app/plugins/templates/plugins/plugin_detail.html +++ b/qgis-app/plugins/templates/plugins/plugin_detail.html @@ -164,9 +164,16 @@

{{ object.name }}
{% trans "Author's email"%}
{{ object.email }}
{% endif %} + {% if object.display_created_by %} +
{% trans "Created by"%}
+
+ {{ object.created_by }} +
+ + {% endif %}
{% trans "Maintainer"%}
- {{ object.created_by }} + {{ object.maintainer }}
{% if object.owners.count %}
{% trans "Collaborators"%}
diff --git a/qgis-app/plugins/templates/plugins/plugin_form.html b/qgis-app/plugins/templates/plugins/plugin_form.html index 4555a745..86edcd27 100644 --- a/qgis-app/plugins/templates/plugins/plugin_form.html +++ b/qgis-app/plugins/templates/plugins/plugin_form.html @@ -66,7 +66,7 @@

{{ form_title }} {{ plugin }}

let element = document.getElementById('id_owners'); if(element) { $('#id_owners').chosen({ - placeholder_text_multiple: "Select Some Owners", + placeholder_text_multiple: "Select Some Collaborators", no_results_text: "Oops, nothing found!" }); clearInterval(checkElement); diff --git a/qgis-app/plugins/tests/test_change_maintainer.py b/qgis-app/plugins/tests/test_change_maintainer.py new file mode 100644 index 00000000..a9357f6f --- /dev/null +++ b/qgis-app/plugins/tests/test_change_maintainer.py @@ -0,0 +1,101 @@ +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 PluginForm + +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.save() + + @patch("plugins.tasks.generate_plugins_xml.delay", new=do_nothing) + @patch("plugins.validator._check_url_link", new=do_nothing) + def test_change_maintainer(self): + """ + Test change maintainer for plugin update + """ + package_name = self.plugin.package_name + self.url_plugin_update = reverse('plugin_update', args=[package_name]) + self.url_add_version = reverse('version_create', args=[package_name]) + + # Test GET request + response = self.client.get(self.url_plugin_update) + self.assertEqual(response.status_code, 200) + self.assertIsInstance(response.context['form'], PluginForm) + self.assertEqual(response.context['form']['maintainer'].value(), self.user.pk) + + + # Test POST request to change maintainer + + response = self.client.post(self.url_plugin_update, { + 'description': self.plugin.description, + 'about': self.plugin.about, + 'author': self.plugin.author, + 'email': self.plugin.email, + 'tracker': self.plugin.tracker, + 'repository': self.plugin.repository, + 'maintainer': 1, + }) + self.assertEqual(response.status_code, 302) + self.assertEqual(Plugin.objects.get(name='Test Plugin').maintainer.pk, 1) + + # Test POST request with new version + + 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.assertEqual(Plugin.objects.get(name='Test Plugin').maintainer.pk, 1) + + def tearDown(self): + self.client.logout() From 55cc6a5791813a32e474c4e93c7cb1d8f8b120cb Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Mon, 25 Dec 2023 09:59:23 +0300 Subject: [PATCH 5/8] Hide login button when logged out (#324) --- qgis-app/templates/base.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qgis-app/templates/base.html b/qgis-app/templates/base.html index a1c84319..0160ce9c 100644 --- a/qgis-app/templates/base.html +++ b/qgis-app/templates/base.html @@ -51,10 +51,6 @@ {% if user.is_authenticated %} - {% else %} - {% endif %}