Skip to content

Commit

Permalink
Add maintainer field to plugin update (#316)
Browse files Browse the repository at this point in the history
* Add maintainer field to plugin update

* Add maintainer and display_created_by fields

---------

Co-authored-by: Dimas Ciputra <dimas.ciputra@gmail.com>
  • Loading branch information
Xpirix and dimasciput authored Dec 23, 2023
1 parent 6fe3124 commit 5b3bdd9
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 2 deletions.
15 changes: 15 additions & 0 deletions qgis-app/plugins/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions qgis-app/plugins/migrations/0005_plugin_maintainer.py
Original file line number Diff line number Diff line change
@@ -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),
]
18 changes: 18 additions & 0 deletions qgis-app/plugins/migrations/0006_plugin_display_created_by.py
Original file line number Diff line number Diff line change
@@ -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'),
),
]
19 changes: 19 additions & 0 deletions qgis-app/plugins/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=_(
Expand Down Expand Up @@ -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
Expand All @@ -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)


Expand Down
9 changes: 8 additions & 1 deletion qgis-app/plugins/templates/plugins/plugin_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,16 @@ <h2>{{ object.name }}
<dt>{% trans "Author's email"%}</dt>
<dd> <a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
{% endif %}
{% if object.display_created_by %}
<dt>{% trans "Created by"%}</dt>
<dd>
<a href="{% url "user_details" object.created_by %}">{{ object.created_by }}</a>
</dd>

{% endif %}
<dt>{% trans "Maintainer"%}</dt>
<dd>
<a href="{% url "user_details" object.created_by %}">{{ object.created_by }}</a>
<a href="{% url "user_details" object.maintainer %}">{{ object.maintainer }}</a>
</dd>
{% if object.owners.count %}
<dt>{% trans "Collaborators"%}</dt>
Expand Down
2 changes: 1 addition & 1 deletion qgis-app/plugins/templates/plugins/plugin_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ <h2>{{ form_title }} {{ plugin }}</h2>
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);
Expand Down
101 changes: 101 additions & 0 deletions qgis-app/plugins/tests/test_change_maintainer.py
Original file line number Diff line number Diff line change
@@ -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()

0 comments on commit 5b3bdd9

Please sign in to comment.