[Patchew-devel] [PATCH v2 2/4] models: convert tags from property to field

Paolo Bonzini pbonzini at redhat.com
Fri Sep 28 14:58:43 UTC 2018


Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
 api/migrations/0035_message_tags.py          | 22 ++++++++++
 api/migrations/0036_populate_message_tags.py | 43 ++++++++++++++++++++
 api/models.py                                |  1 +
 api/rest.py                                  |  5 ++-
 api/views.py                                 | 13 +++++-
 mods/git.py                                  |  5 ++-
 mods/tags.py                                 | 13 ++----
 patchew-cli                                  |  5 ++-
 www/urls.py                                  |  2 +-
 9 files changed, 91 insertions(+), 18 deletions(-)
 create mode 100644 api/migrations/0035_message_tags.py
 create mode 100644 api/migrations/0036_populate_message_tags.py

diff --git a/api/migrations/0035_message_tags.py b/api/migrations/0035_message_tags.py
new file mode 100644
index 0000000..4354bba
--- /dev/null
+++ b/api/migrations/0035_message_tags.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.13 on 2018-09-27 10:09
+from __future__ import unicode_literals
+
+from django.db import migrations
+import jsonfield.encoder
+import jsonfield.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('api', '0034_auto_20180822_1106'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='message',
+            name='tags',
+            field=jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
+        ),
+    ]
diff --git a/api/migrations/0036_populate_message_tags.py b/api/migrations/0036_populate_message_tags.py
new file mode 100644
index 0000000..e9f2a70
--- /dev/null
+++ b/api/migrations/0036_populate_message_tags.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations
+from django.db.models import Count
+import json
+
+
+def tags_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.
+    Message = apps.get_model('api', 'Message')
+    MessageProperty = apps.get_model('api', 'MessageProperty')
+    messages = Message.objects.filter(properties__name='tags')
+    for m in messages:
+        mp = m.properties.filter(name='tags')[0]
+        m.tags = mp.value
+        m.save()
+    MessageProperty.objects.filter(name='tags').delete()
+
+def tags_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.
+    Message = apps.get_model('api', 'Message')
+    MessageProperty = apps.get_model('api', 'MessageProperty')
+    messages = Message.objects.exclude(tags=[])
+    for m in messages:
+        mp = MessageProperty(message=m,
+                             name='tags',
+                             value=m.tags,
+                             blob=False)
+        mp.save()
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('api', '0035_message_tags'),
+    ]
+
+    operations = [
+        migrations.RunPython(tags_from_property,
+                             reverse_code=tags_to_property),
+    ]
diff --git a/api/models.py b/api/models.py
index a6639b7..ab0bd06 100644
--- a/api/models.py
+++ b/api/models.py
@@ -460,6 +460,7 @@ class Message(models.Model):
     version = models.PositiveSmallIntegerField(default=0)
     sender = jsonfield.JSONCharField(max_length=4096, db_index=True)
     recipients = jsonfield.JSONField()
+    tags = jsonfield.JSONField(default=[])
     prefixes = jsonfield.JSONField(blank=True)
     is_series_head = models.BooleanField()
     is_complete = models.BooleanField(default=False)
diff --git a/api/rest.py b/api/rest.py
index 8789e25..61df8cd 100644
--- a/api/rest.py
+++ b/api/rest.py
@@ -19,7 +19,7 @@ from .search import SearchEngine
 from rest_framework import (permissions, serializers, viewsets, filters,
     mixins, generics, renderers, status)
 from rest_framework.decorators import detail_route, action
-from rest_framework.fields import SerializerMethodField, CharField, JSONField, EmailField
+from rest_framework.fields import SerializerMethodField, CharField, JSONField, EmailField, ListField
 from rest_framework.relations import HyperlinkedIdentityField
 from rest_framework.response import Response
 import rest_framework
@@ -238,11 +238,12 @@ class AddressSerializer(serializers.Serializer):
 class BaseMessageSerializer(serializers.ModelSerializer):
     class Meta:
         model = Message
-        fields = ('resource_uri', 'message_id', 'subject', 'date', 'sender', 'recipients')
+        fields = ('resource_uri', 'message_id', 'subject', 'date', 'sender', 'recipients', 'tags')
 
     resource_uri = HyperlinkedMessageField(view_name='messages-detail')
     recipients = AddressSerializer(many=True)
     sender = AddressSerializer()
+    tags = ListField(child=CharField(), required=False)
    
     def create(self, validated_data):
         validated_data['recipients'] = self.fields['recipients'].create(validated_data['recipients'])
diff --git a/api/views.py b/api/views.py
index 32bceab..f224a63 100644
--- a/api/views.py
+++ b/api/views.py
@@ -151,11 +151,18 @@ class SetProjectPropertiesView(APILoginRequiredView):
         for k, v in properties.items():
             po.set_property(k, v)
 
+def get_properties(m):
+    r = m.get_properties()
+    # for compatibility with patchew-cli's applier mode
+    if m.tags:
+        r['tags'] = m.tags
+    return r
+
 def prepare_patch(p):
     r = {"subject": p.subject,
          "message-id": p.message_id,
          "mbox": p.get_mbox(),
-         "properties": p.get_properties(),
+         "properties": get_properties(p)
          }
     return r
 
@@ -173,7 +180,9 @@ def prepare_series(request, s, fields=None):
     if want_field("patches"):
         r["patches"] = [prepare_patch(x) for x in s.get_patches()]
     if want_field("properties"):
-        r["properties"] = s.get_properties()
+        r["properties"] = get_properties(s)
+    if want_field("tags"):
+        r["tags"] = s.tags
     if want_field("is_complete"):
         r["is_complete"] = s.is_complete
     if fields:
diff --git a/mods/git.py b/mods/git.py
index a985ba4..58e4bd2 100644
--- a/mods/git.py
+++ b/mods/git.py
@@ -228,7 +228,7 @@ class GitModule(PatchewModule):
                                                                           project)})
 
     def get_base(self, series):
-        for tag in series.get_property("tags", []):
+        for tag in series.tags:
             if not tag.startswith("Based-on:"):
                 continue
             base_id = tag[len("Based-on:"):].strip()
@@ -279,7 +279,8 @@ class ApplierGetView(APILoginRequiredView):
         if not m:
             return None
 
-        response = prepare_series(request, m, fields=["project", "message-id", "patches", "properties"])
+        response = prepare_series(request, m, fields=["project", "message-id", "patches",
+                                                      "properties", "tags"])
 
         po = m.project
         for prop in ["git.push_to", "git.public_repo", "git.url_template"]:
diff --git a/mods/tags.py b/mods/tags.py
index 5ec5bc2..1ac27a7 100644
--- a/mods/tags.py
+++ b/mods/tags.py
@@ -56,10 +56,11 @@ series cover letter, patch mail body and their replies.
         return set([x.strip() for x in tagsconfig.split(",") if x.strip()] + BUILT_IN_TAGS)
 
     def update_tags(self, s):
-        old = s.get_property("tags", [])
+        old = s.tags
         new = self.look_for_tags(s)
         if set(old) != set(new):
-            s.set_property("tags", list(set(new)))
+            s.tags = list(set(new))
+            s.save()
             return True
 
     def on_message_added(self, event, message):
@@ -84,7 +85,7 @@ series cover letter, patch mail body and their replies.
         num_reviewed = 0
         def _find_reviewers(what):
             ret = set()
-            for rev_tag in [x for x in what.get_property("tags", []) if x.lower().startswith(REV_BY_PREFIX.lower())]:
+            for rev_tag in [x for x in what.tags if x.lower().startswith(REV_BY_PREFIX.lower())]:
                 ret.add(parse_address(rev_tag[len(REV_BY_PREFIX):]))
             return ret
         for p in series.get_patches():
@@ -120,12 +121,6 @@ series cover letter, patch mail body and their replies.
             r += self.look_for_tags(x)
         return r
 
-    def get_tags(self, m, request, format):
-        return m.get_property("tags", [])
-
-    def rest_message_fields_hook(self, request, fields):
-        fields['tags'] = PluginMethodField(obj=self)
-
     def prepare_message_hook(self, request, message, detailed):
         if not message.is_series_head:
             return
diff --git a/patchew-cli b/patchew-cli
index c67abd5..b5d6ecb 100755
--- a/patchew-cli
+++ b/patchew-cli
@@ -693,8 +693,9 @@ class ApplyCommand(SubCommand):
                     subprocess.check_output(["git", "log", "-n", "1",
                                              "--format=%b"], cwd=repo) \
                                            .decode('utf-8').splitlines()
-            for t in set(p["properties"].get("tags", []) + \
-                         s["properties"].get("tags", [])):
+            # old servers do not have "tags" directly in the response
+            for t in set(p["properties"].get("tags", []) + p.get("tags", []) + \
+                         s["properties"].get("tags", []) + s.get("tags", [])):
                 if t in commit_message_lines:
                     continue
                 filter_cmd += "echo '%s';" % t
diff --git a/www/urls.py b/www/urls.py
index 5787cbd..21b945c 100644
--- a/www/urls.py
+++ b/www/urls.py
@@ -34,6 +34,6 @@ urlpatterns += [
         url(r"^(?P<project>[^/]*)/info$", views.view_project_detail, name="project_detail"),
         url(r"^(?P<project>[^/]*)/(?P<message_id>[^/]*)/$", views.view_series_detail, name="series_detail"),
         url(r"^(?P<project>[^/]*)/(?P<thread_id>[^/]*)/(?P<message_id>[^/]*)/$", views.view_series_message, name="series_message"),
-        url(r"^(?P<project>[^/]*)/(?P<message_id>[^/]*)/mbox$", views.view_series_mbox, name="mbox"),
+        url(r"^(?P<project>[^/]*)/(?P<message_id>[^/]*)/mbox$", views.view_mbox, name="mbox"),
         url(r"^$", views.view_project_list, name="project_list"),
         ]
-- 
2.17.1





More information about the Patchew-devel mailing list