diff --git a/snipts/admin.py b/snipts/admin.py index dcbc7cc..8729b88 100644 --- a/snipts/admin.py +++ b/snipts/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from snipts.models import Favorite, Snipt +from snipts.models import Favorite, Snipt, SniptLogEntry class SniptAdmin(admin.ModelAdmin): @@ -15,6 +15,13 @@ class SniptAdmin(admin.ModelAdmin): admin.site.register(Snipt, SniptAdmin) +class SniptLogEntryAdmin(admin.ModelAdmin): + readonly_fields = ('user',) + list_display = ('snipt_name', 'user', 'created', 'modified') + +admin.site.register(SniptLogEntry, SniptLogEntryAdmin) + + class FavoriteAdmin(admin.ModelAdmin): readonly_fields = ('snipt', 'user',) list_display = ('snipt', 'user', 'created',) diff --git a/snipts/api.py b/snipts/api.py index 223244b..d2bcdb8 100644 --- a/snipts/api.py +++ b/snipts/api.py @@ -244,6 +244,19 @@ class PublicSniptResource(ModelResource): bundle.data['description_rendered'] = \ linebreaksbr(urlize(bundle.obj.description)) + log_entries = bundle.obj.sniptlogentry_set.all() + bundle_log_entries = [] + + for entry in log_entries: + bundle_log_entries.append({ + 'created': entry.created, + 'user': entry.user, + 'code': entry.code, + 'diff': entry.diff + }) + + bundle.data['log_entries'] = bundle_log_entries + if 'omit_code' in bundle.request.GET: del bundle.data['code'] diff --git a/snipts/migrations/0002_sniptlogentry.py b/snipts/migrations/0002_sniptlogentry.py new file mode 100644 index 0000000..5557190 --- /dev/null +++ b/snipts/migrations/0002_sniptlogentry.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('snipts', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='SniptLogEntry', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('code', models.TextField()), + ('diff', models.TextField()), + ('created', models.DateTimeField(auto_now_add=True)), + ('modified', models.DateTimeField(auto_now=True)), + ('snipt', models.ForeignKey(to='snipts.Snipt')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/snipts/models.py b/snipts/models.py index af5b23a..cd7c7c9 100644 --- a/snipts/models.py +++ b/snipts/models.py @@ -1,4 +1,5 @@ import datetime +import difflib import hashlib import random import re @@ -47,6 +48,18 @@ class Snipt(models.Model): modified = models.DateTimeField(auto_now=True, editable=False) publish_date = models.DateTimeField(blank=True, null=True) + def _unidiff_output(self, expected, actual): + expected = expected.splitlines(1) + actual = actual.splitlines(1) + + diff = difflib.unified_diff(expected, actual) + + return ''.join(diff) + + def __init__(self, *args, **kwargs): + super(Snipt, self).__init__(*args, **kwargs) + self.original_code = self.code + def save(self, *args, **kwargs): if not self.slug: @@ -156,7 +169,16 @@ class Snipt(models.Model): .replace('background: #202020', '')) self.embedded = embedded - return super(Snipt, self).save(*args, **kwargs) + snipt = super(Snipt, self).save(*args, **kwargs) + + diff = self._unidiff_output(self.original_code or '', self.code) + log_entry = SniptLogEntry(user=self.user, + snipt=self, + code=self.code, + diff=diff) + log_entry.save() + + return snipt def __unicode__(self): return self.title @@ -275,6 +297,23 @@ class Snipt(models.Model): return get_lexer_by_name(self.lexer).name +class SniptLogEntry(models.Model): + """An individual log entry for a Snipt changeset.""" + + user = models.ForeignKey(User) + snipt = models.ForeignKey(Snipt) + + code = models.TextField() + diff = models.TextField() + + created = models.DateTimeField(auto_now_add=True, editable=False) + modified = models.DateTimeField(auto_now=True, editable=False) + + @property + def snipt_name(self): + return self.snipt.title or 'Untitled' + + class Favorite(models.Model): snipt = models.ForeignKey(Snipt) user = models.ForeignKey(User)