From: Radek Czajka Date: Thu, 30 Jun 2011 15:58:46 +0000 (+0200) Subject: django 1.3, comments on books, last activity log, some minor changes X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/9249e6ddc35e7cc7077fa5035fbc27397fbb70a9 django 1.3, comments on books, last activity log, some minor changes --- diff --git a/apps/dvcs/admin.py b/apps/dvcs/admin.py index 984798df..f6a1ab39 100644 --- a/apps/dvcs/admin.py +++ b/apps/dvcs/admin.py @@ -1,6 +1,11 @@ -from django.contrib.admin import site -from dvcs.models import Document, Change, Tag +from django.contrib import admin -site.register(Tag) -site.register(Document) -site.register(Change) +from dvcs import models + + +class TagAdmin(admin.ModelAdmin): + list_display = ['name', 'slug', 'ordering'] + +admin.site.register(models.Tag, TagAdmin) +admin.site.register(models.Document) +admin.site.register(models.Change) diff --git a/apps/dvcs/migrations/0001_initial.py b/apps/dvcs/migrations/0001_initial.py index 6bff0950..bf8d3e24 100644 --- a/apps/dvcs/migrations/0001_initial.py +++ b/apps/dvcs/migrations/0001_initial.py @@ -4,7 +4,6 @@ from south.db import db from south.v2 import SchemaMigration from django.db import models - class Migration(SchemaMigration): def forwards(self, orm): @@ -22,7 +21,8 @@ class Migration(SchemaMigration): db.create_table('dvcs_change', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), - ('author_desc', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), + ('author_name', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), + ('author_email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), ('patch', self.gf('django.db.models.fields.TextField')(blank=True)), ('tree', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['dvcs.Document'])), ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)), @@ -48,8 +48,10 @@ class Migration(SchemaMigration): # Adding model 'Document' db.create_table('dvcs_document', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('creator', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_documents', null=True, to=orm['auth.User'])), ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['dvcs.Change'], null=True, blank=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['dvcs.Tag'], null=True, blank=True)), )) db.send_create_signal('dvcs', ['Document']) @@ -84,7 +86,7 @@ class Migration(SchemaMigration): 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) }, 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), @@ -116,7 +118,8 @@ class Migration(SchemaMigration): 'dvcs.change': { 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'Change'}, 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'author_desc': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), @@ -130,9 +133,11 @@ class Migration(SchemaMigration): }, 'dvcs.document': { 'Meta': {'object_name': 'Document'}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_documents'", 'null': 'True', 'to': "orm['auth.User']"}), 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['dvcs.Change']", 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Tag']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) }, 'dvcs.tag': { 'Meta': {'ordering': "['ordering']", 'object_name': 'Tag'}, diff --git a/apps/dvcs/migrations/0002_auto__add_field_document_user__add_field_document_stage.py b/apps/dvcs/migrations/0002_auto__add_field_document_user__add_field_document_stage.py deleted file mode 100644 index 41ab9b24..00000000 --- a/apps/dvcs/migrations/0002_auto__add_field_document_user__add_field_document_stage.py +++ /dev/null @@ -1,96 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding field 'Document.user' - db.add_column('dvcs_document', 'user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True), keep_default=False) - - # Adding field 'Document.stage' - db.add_column('dvcs_document', 'stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['dvcs.Tag'], null=True), keep_default=False) - - - def backwards(self, orm): - - # Deleting field 'Document.user' - db.delete_column('dvcs_document', 'user_id') - - # Deleting field 'Document.stage' - db.delete_column('dvcs_document', 'stage_id') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'dvcs.change': { - 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'Change'}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'author_desc': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'patch': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['dvcs.Tag']", 'symmetrical': 'False'}), - 'tree': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Document']"}) - }, - 'dvcs.document': { - 'Meta': {'object_name': 'Document'}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_documents'", 'null': 'True', 'to': "orm['auth.User']"}), - 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['dvcs.Change']", 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Tag']", 'null': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) - }, - 'dvcs.tag': { - 'Meta': {'ordering': "['ordering']", 'object_name': 'Tag'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'ordering': ('django.db.models.fields.IntegerField', [], {}), - 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['dvcs'] diff --git a/apps/dvcs/models.py b/apps/dvcs/models.py index f81f2cab..86f66bc9 100644 --- a/apps/dvcs/models.py +++ b/apps/dvcs/models.py @@ -60,7 +60,8 @@ class Change(models.Model): Data contains a pickled diff needed to reproduce the initial document. """ author = models.ForeignKey(User, null=True, blank=True) - author_desc = models.CharField(max_length=128, null=True, blank=True) + author_name = models.CharField(max_length=128, null=True, blank=True) + author_email = models.CharField(max_length=128, null=True, blank=True) patch = models.TextField(blank=True) tree = models.ForeignKey('Document') revision = models.IntegerField(db_index=True) @@ -94,7 +95,10 @@ class Change(models.Model): self.author.last_name, self.author.email) else: - return self.author_desc + return "%s <%s>" % ( + self.author_name, + self.author_email + ) def save(self, *args, **kwargs): @@ -127,20 +131,22 @@ class Change(models.Model): return text def make_child(self, patch, description, author=None, - author_desc=None, tags=None): + author_name=None, author_email=None, tags=None): ch = self.children.create(patch=patch, tree=self.tree, author=author, - author_desc=author_desc, + author_name=author_name, + author_email=author_email, description=description) if tags is not None: ch.tags = tags return ch def make_merge_child(self, patch, description, author=None, - author_desc=None, tags=None): + author_name=None, author_email=None, tags=None): ch = self.merge_children.create(patch=patch, tree=self.tree, author=author, - author_desc=author_desc, + author_name=author_name, + author_email=author_email, description=description, tags=tags) if tags is not None: @@ -150,7 +156,8 @@ class Change(models.Model): def apply_to(self, text): return mdiff.patch(text, pickle.loads(self.patch.encode('ascii'))) - def merge_with(self, other, author=None, author_desc=None, + def merge_with(self, other, author=None, + author_name=None, author_email=None, description=u"Automatic merge."): assert self.tree_id == other.tree_id # same tree if other.parent_id == self.pk: @@ -166,7 +173,9 @@ class Change(models.Model): patch = self.make_patch(local, result) return self.children.create( patch=patch, merge_parent=other, tree=self.tree, - author=author, author_desc=author_desc, + author=author, + author_name=author_name, + author_email=author_email, description=description) def revert(self, **kwargs): @@ -225,7 +234,8 @@ class Document(models.Model): patch = kwargs['patch'] author = kwargs.get('author', None) - author_desc = kwargs.get('author_desc', None) + author_name = kwargs.get('author_name', None) + author_email = kwargs.get('author_email', None) tags = kwargs.get('tags', []) if tags: # set stage to next tag after the commited one @@ -234,15 +244,18 @@ class Document(models.Model): old_head = self.head if parent != old_head: change = parent.make_merge_child(patch, author=author, - author_desc=author_desc, + author_name=author_name, + author_email=author_email, description=kwargs.get('description', ''), tags=tags) # not Fast-Forward - perform a merge self.head = old_head.merge_with(change, author=author, - author_desc=author_desc) + author_name=author_name, + author_email=author_email) else: self.head = parent.make_child(patch, author=author, - author_desc=author_desc, + author_name=author_name, + author_email=author_email, description=kwargs.get('description', ''), tags=tags) diff --git a/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py b/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py index 3db141ae..deb649f9 100644 --- a/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py +++ b/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py @@ -15,6 +15,7 @@ from slughifi import slughifi META_REGEX = re.compile(r'\s*', re.DOTALL | re.MULTILINE) STAGE_TAGS_RE = re.compile(r'^#stage-finished: (.*)$', re.MULTILINE) +AUTHOR_RE = re.compile(r'\s*(.*?)\s*<(.*)>\s*') def urlunquote(url): @@ -84,8 +85,7 @@ def migrate_file_from_hg(orm, fname, entry): chunk = orm.Chunk.objects.create( book=book, number=1, - slug='1', - comment='cz. 1') + slug='1') head = orm['dvcs.Change'].objects.create( tree=chunk, revision=-1, @@ -123,13 +123,27 @@ def migrate_file_from_hg(orm, fname, entry): description = STAGE_TAGS_RE.sub('', description) + author = author_name = author_email = None + author_desc = fctx.user().decode("utf-8", 'replace') + m = AUTHOR_RE.match(author_desc) + if m: + try: + author = orm['auth.User'].objects.get(username=m.group(1), email=m.group(2)) + except orm['auth.User'].DoesNotExist: + author_name = m.group(1) + author_email = m.group(2) + else: + author_name = author_desc + head = orm['dvcs.Change'].objects.create( tree=chunk, revision=rev + 1, patch=make_patch(old_data, data), created_at=datetime.datetime.fromtimestamp(fctx.date()[0]), description=description, - author_desc=fctx.user().decode("utf-8", 'replace'), + author=author, + author_name=author_name, + author_email=author_email, parent=chunk.head ) head.tags = tags @@ -252,7 +266,8 @@ class Migration(SchemaMigration): 'dvcs.change': { 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'Change'}, 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'author_desc': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), diff --git a/apps/wiki/models.py b/apps/wiki/models.py index 9eb77a5c..28fdab8b 100644 --- a/apps/wiki/models.py +++ b/apps/wiki/models.py @@ -157,7 +157,7 @@ class Chunk(dvcs_models.Document): book = models.ForeignKey(Book, editable=False) number = models.IntegerField() slug = models.SlugField() - comment = models.CharField(max_length=255) + comment = models.CharField(max_length=255, blank=True) class Meta: unique_together = [['book', 'number'], ['book', 'slug']] @@ -177,8 +177,13 @@ class Chunk(dvcs_models.Document): return cls.objects.get(book__slug=slug, slug=chunk) def pretty_name(self): - return "%s, %s (%d/%d)" % (self.book.title, self.comment, - self.number, len(self.book)) + title = self.book.title + if self.comment: + title += ", %s" % self.comment + count = len(self.book) + if count > 1: + title += " (%d/%d)" % (self.number, len(self.book)) + return title def split(self, slug, comment='', creator=None): """ Create an empty chunk after this one """ diff --git a/apps/wiki/templates/wiki/book_detail.html b/apps/wiki/templates/wiki/book_detail.html index 347b7a37..84d2097b 100755 --- a/apps/wiki/templates/wiki/book_detail.html +++ b/apps/wiki/templates/wiki/book_detail.html @@ -1,5 +1,5 @@ {% extends "wiki/base.html" %} -{% load i18n %} +{% load comments i18n %} {% block leftcolumn %} @@ -97,6 +97,7 @@ {% endblock leftcolumn %} {% block rightcolumn %} - +{% render_comment_list for book %} +{% render_comment_form for book %} {% endblock rightcolumn %} diff --git a/apps/wiki/templates/wiki/document_create_missing.html b/apps/wiki/templates/wiki/document_create_missing.html index 351e87a2..9414f7cb 100644 --- a/apps/wiki/templates/wiki/document_create_missing.html +++ b/apps/wiki/templates/wiki/document_create_missing.html @@ -3,6 +3,7 @@ {% block leftcolumn %}
+ {% csrf_token %} {{ form.as_p }}

@@ -10,4 +11,4 @@ {% endblock leftcolumn %} {% block rightcolumn %} -{% endblock rightcolumn %} \ No newline at end of file +{% endblock rightcolumn %} diff --git a/apps/wiki/templates/wiki/document_details_base.html b/apps/wiki/templates/wiki/document_details_base.html index 3eda939b..5f98b733 100644 --- a/apps/wiki/templates/wiki/document_details_base.html +++ b/apps/wiki/templates/wiki/document_details_base.html @@ -20,6 +20,7 @@ {{ chunk.book.gallery }} {{ revision }} + {{ request.GET.diff }} {% block meta-extra %} {% endblock %} diff --git a/apps/wiki/templates/wiki/document_list.html b/apps/wiki/templates/wiki/document_list.html index 9525078c..2a0a5efa 100644 --- a/apps/wiki/templates/wiki/document_list.html +++ b/apps/wiki/templates/wiki/document_list.html @@ -94,4 +94,7 @@ $(function() { {% endfor %} + +

{% trans "Recent activity" %}

+ {% wall %} {% endblock rightcolumn %} diff --git a/apps/wiki/templates/wiki/document_upload.html b/apps/wiki/templates/wiki/document_upload.html index 929ee4db..f7af2cef 100644 --- a/apps/wiki/templates/wiki/document_upload.html +++ b/apps/wiki/templates/wiki/document_upload.html @@ -12,6 +12,7 @@

+{% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/wall.html b/apps/wiki/templates/wiki/wall.html new file mode 100755 index 00000000..ed4685a0 --- /dev/null +++ b/apps/wiki/templates/wiki/wall.html @@ -0,0 +1,32 @@ +{% load i18n %} +{% load gravatar %} + + diff --git a/apps/wiki/templatetags/wiki.py b/apps/wiki/templatetags/wiki.py index 1fb1a2ea..337afa65 100644 --- a/apps/wiki/templatetags/wiki.py +++ b/apps/wiki/templatetags/wiki.py @@ -1,10 +1,13 @@ from __future__ import absolute_import from django.core.urlresolvers import reverse +from django.contrib.comments.models import Comment from django.template.defaultfilters import stringfilter from django import template from django.utils.translation import ugettext as _ +from wiki.models import Book +from dvcs.models import Change register = template.Library() @@ -39,3 +42,99 @@ def main_tabs(context): tabs.append(Tab('admin', _('Admin'), reverse("admin:index"))) return {"tabs": tabs, "active_tab": active} + + +class WallItem(object): + title = '' + summary = '' + url = '' + timestamp = '' + user = None + email = '' + + def __init__(self, tag): + self.tag = tag + + def get_email(self): + if self.user: + return self.user.email + else: + return self.email + + +def changes_wall(max_len): + qs = Change.objects.filter(revision__gt=-1).order_by('-created_at').select_related() + qs = qs[:max_len] + for item in qs: + tag = 'stage' if item.tags.count() else 'change' + chunk = item.tree.chunk + w = WallItem(tag) + w.title = chunk.pretty_name() + w.summary = item.description + w.url = reverse('wiki_editor', + args=[chunk.book.slug, chunk.slug]) + '?diff=%d' % item.revision + w.timestamp = item.created_at + w.user = item.author + w.email = item.author_email + yield w + + +def published_wall(max_len): + qs = Book.objects.exclude(last_published=None).order_by('-last_published') + qs = qs[:max_len] + for item in qs: + w = WallItem('publish') + w.title = item.title + w.summary = item.title + w.url = chunk.book.get_absolute_url() + w.timestamp = item.last_published + w.user = item.last_published_by + yield w + + +def comments_wall(max_len): + qs = Comment.objects.filter(is_public=True).select_related().order_by('-submit_date') + qs = qs[:max_len] + for item in qs: + w = WallItem('comment') + w.title = item.content_object + w.summary = item.comment + w.url = item.content_object.get_absolute_url() + w.timestamp = item.submit_date + w.user = item.user + w.email = item.user_email + yield w + + +def big_wall(max_len, *args): + """ + Takes some WallItem iterators and zips them into one big wall. + Input iterators must already be sorted by timestamp. + """ + subwalls = [] + for w in args: + try: + subwalls.append([next(w), w]) + except StopIteration: + pass + + while max_len and subwalls: + i, next_item = max(enumerate(subwalls), key=lambda x: x[1][0].timestamp) + yield next_item[0] + max_len -= 1 + try: + next_item[0] = next(next_item[1]) + except StopIteration: + del subwalls[i] + + +@register.inclusion_tag("wiki/wall.html", takes_context=True) +def wall(context, max_len=10): + return { + "request": context['request'], + "STATIC_URL": context['STATIC_URL'], + "wall": big_wall(max_len, + changes_wall(max_len), + published_wall(max_len), + comments_wall(max_len), + )} diff --git a/redakcja/settings/__init__.py b/redakcja/settings/__init__.py index 6f1c094e..600533b9 100644 --- a/redakcja/settings/__init__.py +++ b/redakcja/settings/__init__.py @@ -1,12 +1,17 @@ from __future__ import absolute_import +from os import path from redakcja.settings.common import * -DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. -DATABASE_NAME = PROJECT_ROOT + '/dev.sqlite' # Or path to database file if using sqlite3. -DATABASE_USER = '' # Not used with sqlite3. -DATABASE_PASSWORD = '' # Not used with sqlite3. -DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. -DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'), # Or path to database file if using sqlite3. + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} try: LOGGING_CONFIG_FILE diff --git a/redakcja/settings/common.py b/redakcja/settings/common.py index 36c54b00..f55a877b 100644 --- a/redakcja/settings/common.py +++ b/redakcja/settings/common.py @@ -36,6 +36,8 @@ SITE_ID = 1 # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = True +USE_L10N = True + # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" @@ -69,12 +71,14 @@ TEMPLATE_CONTEXT_PROCESSORS = ( "django.core.context_processors.debug", "django.core.context_processors.i18n", "redakcja.context_processors.settings", # this is instead of media + 'django.core.context_processors.csrf', "django.core.context_processors.request", ) MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -112,6 +116,7 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.admin', 'django.contrib.admindocs', + 'django.contrib.comments', 'django_cas', 'compress', @@ -119,6 +124,7 @@ INSTALLED_APPS = ( 'sorl.thumbnail', 'filebrowser', 'pagination', + 'gravatar', 'dvcs', 'wiki', diff --git a/redakcja/static/css/filelist.css b/redakcja/static/css/filelist.css index 4c5ffb3f..61e6af22 100644 --- a/redakcja/static/css/filelist.css +++ b/redakcja/static/css/filelist.css @@ -58,7 +58,7 @@ body { -#file-list { +#wiki_layout_left_column { overflow: visible; float: left; /*max-width: 50%;*/ @@ -67,7 +67,7 @@ body { } -#last-edited-list { +#wiki_layout_right_column { float: left; max-width: 35%; margin-left: 5%; diff --git a/redakcja/static/js/wiki/view_history.js b/redakcja/static/js/wiki/view_history.js index fe3af69a..bd6b27b0 100644 --- a/redakcja/static/js/wiki/view_history.js +++ b/redakcja/static/js/wiki/view_history.js @@ -5,6 +5,20 @@ options.callback = function() { var self = this; + if (CurrentDocument.diff) { + rev_from = CurrentDocument.diff[0]; + rev_to = CurrentDocument.diff[1]; + this.doc.fetchDiff({ + from: rev_from, + to: rev_to, + success: function(doc, data){ + var result = $.wiki.newTab(doc, ''+rev_from +' -> ' + rev_to, 'DiffPerspective'); + + $(result.view).html(data); + $.wiki.switchToTab(result.tab); + } + }); + } // first time page is rendered $('#make-diff-button').click(function() { diff --git a/redakcja/static/js/wiki/wikiapi.js b/redakcja/static/js/wiki/wikiapi.js index a1f2fb92..cbed73b8 100644 --- a/redakcja/static/js/wiki/wikiapi.js +++ b/redakcja/static/js/wiki/wikiapi.js @@ -71,6 +71,17 @@ this.readonly = !!$("*[data-key='readonly']", meta).text(); this.galleryLink = $("*[data-key='gallery']", meta).text(); + + var diff = $("*[data-key='diff']", meta).text(); + diff = diff.split(','); + if (diff.length == 2 && diff[0] < diff[1]) + this.diff = diff; + else if (diff.length == 1) { + diff = parseInt(diff); + if (diff != NaN) + this.diff = [diff - 1, diff]; + } + this.galleryImages = []; this.text = null; this.has_local_changes = false; diff --git a/redakcja/urls.py b/redakcja/urls.py index 8aa569b2..3fd6ff52 100644 --- a/redakcja/urls.py +++ b/redakcja/urls.py @@ -18,6 +18,8 @@ urlpatterns = patterns('', url(r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/', include(admin.site.urls)), + (r'^comments/', include('django.contrib.comments.urls')), + url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/documents/'}), url(r'^documents/', include('wiki.urls')), url(r'^storage/', include('dvcs.urls')), diff --git a/requirements.txt b/requirements.txt index 6ba77393..c5d6b044 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,10 +10,11 @@ httplib2 # oauth2 dependency # git+git://github.com/fnp/librarian.git@master#egg=librarian ## Django -Django>=1.1.1,<1.2 +Django>=1.3,<1.4 sorl-thumbnail>=3.2 django-maintenancemode>=0.9 django-pagination +django-gravatar # migrations south>=0.6