Create history entries for fields that are changed on a patch
authorMagnus Hagander <magnus@hagander.net>
Sun, 18 Aug 2013 17:12:11 +0000 (19:12 +0200)
committerMagnus Hagander <magnus@hagander.net>
Sun, 18 Aug 2013 17:12:11 +0000 (19:12 +0200)
pgcommitfest/commitfest/models.py
pgcommitfest/commitfest/util.py [new file with mode: 0644]
pgcommitfest/commitfest/views.py

index 2538e083fa630dc81d721ee1870c4e8cb5c3cd31..090804b10a8431f37beb661277ce11add1e2c82c 100644 (file)
@@ -3,6 +3,8 @@ from django.contrib.admin.models import User
 
 from datetime import datetime
 
+from util import DiffableModel
+
 # We have few enough of these, and it's really the only thing we
 # need to extend from the user model, so just create a separate
 # class.
@@ -52,7 +54,7 @@ class Topic(models.Model):
                return self.topic
 
 
-class Patch(models.Model):
+class Patch(models.Model, DiffableModel):
        name = models.CharField(max_length=500, blank=False, null=False, verbose_name='Description')
        topic = models.ForeignKey(Topic, blank=False, null=False)
 
@@ -81,6 +83,10 @@ class Patch(models.Model):
        # that's attached to this message.
        lastmail = models.DateTimeField(blank=True, null=True)
 
+       map_manytomany_for_diff = {
+               'authors': 'authors_string',
+               'reviewers': 'reviewers_string',
+               }
        # Some accessors
        @property
        def authors_string(self):
diff --git a/pgcommitfest/commitfest/util.py b/pgcommitfest/commitfest/util.py
new file mode 100644 (file)
index 0000000..862ee3d
--- /dev/null
@@ -0,0 +1,35 @@
+from django.forms.models import model_to_dict
+
+
+class DiffableModel(object):
+       """
+       Make it possible to diff a model.
+    """
+
+       def __init__(self, *args, **kwargs):
+               super(DiffableModel, self).__init__(*args, **kwargs)
+               self.__initial = self._dict
+
+       @property
+       def diff(self):
+               manytomanyfieldnames = [f.name for f in self._meta.many_to_many]
+               d1 = self.__initial
+               d2 = self._dict
+               diffs = dict([(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]])
+               if hasattr(self, 'map_manytomany_for_diff'):
+                       for k,v in diffs.items():
+                               if k in manytomanyfieldnames and self.map_manytomany_for_diff.has_key(k):
+                                       # Try to show the display name instead here
+                                       newvalue = getattr(self, self.map_manytomany_for_diff[k])
+                                       diffs[k] = (v[0], newvalue)
+               return diffs
+
+       def save(self, *args, **kwargs):
+               super(DiffableModel, self).save(*args, **kwargs)
+               self.__initial = self._dict
+
+       @property
+       def _dict(self):
+               fields = [field.name for field in self._meta.fields]
+               fields.extend([field.name for field in self._meta.many_to_many])
+               return model_to_dict(self, fields=fields)
index 6fc23a1c803683f3292a9c2d3b5b385bee69a421..1a8ed82264fe0685970b7c2732a2bd9d92de07d0 100644 (file)
@@ -113,9 +113,13 @@ def patchform(request, cfid, patchid):
                        r = form.save(commit=False)
                        # Fill out any locked fields here
 
+                       form.save_m2m()
+
+                       # Track all changes
+                       for field, values in r.diff.items():
+                               PatchHistory(patch=patch, by=request.user, what='Changed %s to %s' % (field, values[1])).save()
                        r.set_modified()
                        r.save()
-                       form.save_m2m()
                        return HttpResponseRedirect('../../%s/' % r.pk)
                # Else fall through and render the page again
        else: