[Patchew-devel] [PATCH 2/3] change "maintainer" from property to many-to-many relation
Paolo Bonzini
pbonzini at redhat.com
Thu Mar 8 09:39:05 UTC 2018
This is the only property that is used by the Patchew core rather than
the plugins. Having it as a relation makes it a bit easier to associates
users with projects in the admin.
(I tested the migration both ways with a local database).
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
api/admin.py | 1 +
api/migrations/0024_project_maintainers.py | 22 +++++++++
.../0025_populate_project_maintainers.py | 52 ++++++++++++++++++++++
api/models.py | 4 +-
tests/patchewtest.py | 2 +
tests/test_project.py | 20 ++++++++-
6 files changed, 99 insertions(+), 2 deletions(-)
create mode 100644 api/migrations/0024_project_maintainers.py
create mode 100644 api/migrations/0025_populate_project_maintainers.py
diff --git a/api/admin.py b/api/admin.py
index a595751..c7ca190 100644
--- a/api/admin.py
+++ b/api/admin.py
@@ -18,6 +18,7 @@ class ProjectPropertyInline(admin.TabularInline):
extra = 0
class ProjectAdmin(admin.ModelAdmin):
+ filter_horizontal = ('maintainers',)
inlines = [
ProjectPropertyInline
]
diff --git a/api/migrations/0024_project_maintainers.py b/api/migrations/0024_project_maintainers.py
new file mode 100644
index 0000000..986d7f6
--- /dev/null
+++ b/api/migrations/0024_project_maintainers.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-03-08 08:15
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('api', '0023_auto_20180308_0810'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='project',
+ name='maintainers',
+ field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
+ ),
+ ]
diff --git a/api/migrations/0025_populate_project_maintainers.py b/api/migrations/0025_populate_project_maintainers.py
new file mode 100644
index 0000000..e029e70
--- /dev/null
+++ b/api/migrations/0025_populate_project_maintainers.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+from django.db.models import Count
+import json
+
+
+def maintainers_from_property(apps, schema_editor):
+ # We can't import the models directly as they may be a newer
+ # version than this migration expects. We use the historical version.
+ Project = apps.get_model('api', 'Project')
+ ProjectProperty = apps.get_model('api', 'ProjectProperty')
+ User = apps.get_model('auth', 'User')
+ projects = Project.objects.filter(projectproperty__name='maintainers')
+ for p in projects:
+ p.maintainers.clear()
+ pp = p.projectproperty_set.filter(name='maintainers')[0]
+ # NOTE: this will fail if the property is a blob
+ maintainers = json.loads(pp.value)
+ users = User.objects.filter(username__in=maintainers)
+ p.maintainers.add(*users)
+ ProjectProperty.objects.filter(name='maintainers').delete()
+
+def maintainers_to_property(apps, schema_editor):
+ # We can't import the models directly as they may be a newer
+ # version than this migration expects. We use the historical version.
+ Project = apps.get_model('api', 'Project')
+ ProjectProperty = apps.get_model('api', 'ProjectProperty')
+ User = apps.get_model('auth', 'User')
+ projects = Project.objects. \
+ annotate(maintainer_count=Count('maintainers')). \
+ filter(maintainer_count__gt=0)
+ for p in projects:
+ maintainers = [u.username for u in p.maintainers.all()]
+ pp = ProjectProperty(project=p,
+ name='maintainers',
+ value=json.dumps(maintainers),
+ blob=False)
+ pp.save()
+ p.maintainers.clear()
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0024_project_maintainers'),
+ ]
+
+ operations = [
+ migrations.RunPython(maintainers_from_property,
+ reverse_code=maintainers_to_property),
+ ]
diff --git a/api/models.py b/api/models.py
index 0c8688a..180d6e3 100644
--- a/api/models.py
+++ b/api/models.py
@@ -75,6 +75,7 @@ class Project(models.Model):
project belongs to. The parent must be a
top project which has
parent_project=NULL""")
+ maintainers = models.ManyToManyField(User,blank=True)
def __str__(self):
return self.name
@@ -125,7 +126,8 @@ class Project(models.Model):
def maintained_by(self, user):
if user.is_superuser:
return True
- if user.username in self.get_property("maintainers", []):
+ if self.maintainers.filter(id=user.id).exists() or \
+ self.get_property("maintainers", []):
return True
return False
diff --git a/tests/patchewtest.py b/tests/patchewtest.py
index 00ecddb..1b0a867 100644
--- a/tests/patchewtest.py
+++ b/tests/patchewtest.py
@@ -55,6 +55,7 @@ class PatchewTestCase(django.test.LiveServerTestCase):
user = User.objects.create_superuser(username or self.user,
self.email,
password or self.password)
+ return user
def create_user(self, username=None, password=None, groups=[]):
user = User.objects.create_user(username or self.user,
@@ -63,6 +64,7 @@ class PatchewTestCase(django.test.LiveServerTestCase):
if groups:
user.groups = [Group.objects.get_or_create(name=g)[0] for g in groups]
user.save()
+ return user
def cli(self, argv):
"""Run patchew-cli command and return (retcode, stdout, stderr)"""
diff --git a/tests/test_project.py b/tests/test_project.py
index 63ca709..25b9661 100755
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -15,7 +15,7 @@ from patchewtest import PatchewTestCase, main
class ProjectTest(PatchewTestCase):
def setUp(self):
- self.create_superuser()
+ self.admin_user = self.create_superuser()
def test_empty(self):
projects = self.get_projects()
@@ -61,5 +61,23 @@ class ProjectTest(PatchewTestCase):
self.assertNotEqual(r, 0)
self.assertNotEqual(b, "")
+ def test_maintainers(self):
+ p = self.add_project("TestProject")
+ u1 = self.create_user(username='buddy', password='abc')
+ u2 = self.create_user(username='mirage', password='def')
+ u2.is_staff = True
+ u2.save()
+ p.maintainers.add(u1)
+ self.assertTrue(p.maintained_by(self.admin_user))
+ self.assertTrue(p.maintained_by(u1))
+ self.assertFalse(p.maintained_by(u2))
+ p.maintainers.add(u2)
+ self.assertTrue(p.maintained_by(u1))
+ self.assertTrue(p.maintained_by(u2))
+ p.maintainers.clear()
+ self.assertTrue(p.maintained_by(self.admin_user))
+ self.assertFalse(p.maintained_by(u1))
+ self.assertFalse(p.maintained_by(u2))
+
if __name__ == '__main__':
main()
--
2.14.3
More information about the Patchew-devel
mailing list