From: Radek Czajka Date: Fri, 1 Jul 2011 13:28:22 +0000 (+0200) Subject: make dvcs models abstract, X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/bb551d54ea65621cae28c6acbfd91b22dc441dae make dvcs models abstract, refactor chunk list rendering --- diff --git a/apps/dvcs/admin.py b/apps/dvcs/admin.py deleted file mode 100644 index f6a1ab39..00000000 --- a/apps/dvcs/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib import admin - -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/fixtures/stages.json b/apps/dvcs/fixtures/stages.json deleted file mode 100644 index fc05d579..00000000 --- a/apps/dvcs/fixtures/stages.json +++ /dev/null @@ -1,83 +0,0 @@ -[ - { - "pk": 1, - "model": "dvcs.tag", - "fields": { - "ordering": 1, - "name": "Autokorekta", - "slug": "first_correction" - } - }, - { - "pk": 2, - "model": "dvcs.tag", - "fields": { - "ordering": 2, - "name": "Tagowanie", - "slug": "tagging" - } - }, - { - "pk": 3, - "model": "dvcs.tag", - "fields": { - "ordering": 3, - "name": "Korekta", - "slug": "proofreading" - } - }, - { - "pk": 4, - "model": "dvcs.tag", - "fields": { - "ordering": 4, - "name": "Sprawdzenie przypis\u00f3w \u017ar\u00f3d\u0142a", - "slug": "annotation-proofreading" - } - }, - { - "pk": 5, - "model": "dvcs.tag", - "fields": { - "ordering": 5, - "name": "Uwsp\u00f3\u0142cze\u015bnienie", - "slug": "modernisation" - } - }, - { - "pk": 6, - "model": "dvcs.tag", - "fields": { - "ordering": 6, - "name": "Przypisy", - "slug": "annotations" - } - }, - { - "pk": 7, - "model": "dvcs.tag", - "fields": { - "ordering": 7, - "name": "Motywy", - "slug": "themes" - } - }, - { - "pk": 8, - "model": "dvcs.tag", - "fields": { - "ordering": 8, - "name": "Ostateczna redakcja literacka", - "slug": "editor-proofreading" - } - }, - { - "pk": 9, - "model": "dvcs.tag", - "fields": { - "ordering": 9, - "name": "Ostateczna redakcja techniczna", - "slug": "technical-editor-proofreading" - } - } -] diff --git a/apps/dvcs/migrations/0001_initial.py b/apps/dvcs/migrations/0001_initial.py deleted file mode 100644 index bf8d3e24..00000000 --- a/apps/dvcs/migrations/0001_initial.py +++ /dev/null @@ -1,151 +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 model 'Tag' - db.create_table('dvcs_tag', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), - ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=64, unique=True, null=True, blank=True)), - ('ordering', self.gf('django.db.models.fields.IntegerField')()), - )) - db.send_create_signal('dvcs', ['Tag']) - - # Adding model 'Change' - 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_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)), - ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['dvcs.Change'])), - ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['dvcs.Change'])), - ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)), - ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)), - ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('dvcs', ['Change']) - - # Adding unique constraint on 'Change', fields ['tree', 'revision'] - db.create_unique('dvcs_change', ['tree_id', 'revision']) - - # Adding M2M table for field tags on 'Change' - db.create_table('dvcs_change_tags', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('change', models.ForeignKey(orm['dvcs.change'], null=False)), - ('tag', models.ForeignKey(orm['dvcs.tag'], null=False)) - )) - db.create_unique('dvcs_change_tags', ['change_id', 'tag_id']) - - # 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')(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']) - - if not db.dry_run: - from django.core.management import call_command - call_command("loaddata", "stages.json") - - - def backwards(self, orm): - - # Removing unique constraint on 'Change', fields ['tree', 'revision'] - db.delete_unique('dvcs_change', ['tree_id', 'revision']) - - # Deleting model 'Tag' - db.delete_table('dvcs_tag') - - # Deleting model 'Change' - db.delete_table('dvcs_change') - - # Removing M2M table for field tags on 'Change' - db.delete_table('dvcs_change_tags') - - # Deleting model 'Document' - db.delete_table('dvcs_document') - - - 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', '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'}), - '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_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'}), - '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', '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'}, - '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/migrations/__init__.py b/apps/dvcs/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/dvcs/models.py b/apps/dvcs/models.py index 86f66bc9..54492402 100644 --- a/apps/dvcs/models.py +++ b/apps/dvcs/models.py @@ -1,6 +1,7 @@ from datetime import datetime from django.db import models +from django.db.models.base import ModelBase from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ from mercurial import mdiff, simplemerge @@ -20,6 +21,7 @@ class Tag(models.Model): _object_cache = {} class Meta: + abstract = True ordering = ['ordering'] def __unicode__(self): @@ -63,7 +65,6 @@ class Change(models.Model): 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) parent = models.ForeignKey('self', @@ -79,9 +80,8 @@ class Change(models.Model): default=datetime.now) publishable = models.BooleanField(default=False) - tags = models.ManyToManyField(Tag) - class Meta: + abstract = True ordering = ('created_at',) unique_together = ['tree', 'revision'] @@ -122,8 +122,7 @@ class Change(models.Model): if self.parent is None and self.merge_parent is not None: return self.apply_to(self.merge_parent.materialize()) - changes = Change.objects.exclude(parent=None).filter( - tree=self.tree, + changes = self.tree.change_set.exclude(parent=None).filter( revision__lte=self.revision).order_by('revision') text = u'' for change in changes: @@ -183,19 +182,60 @@ class Change(models.Model): self.tree.commit(text=self.materialize(), **kwargs) +def create_tag_model(model): + name = model.__name__ + 'Tag' + attrs = { + '__module__': model.__module__, + } + return type(name, (Tag,), attrs) + + +def create_change_model(model): + name = model.__name__ + 'Change' + + attrs = { + '__module__': model.__module__, + 'tree': models.ForeignKey(model, related_name='change_set'), + 'tags': models.ManyToManyField(model.tag_model, related_name='change_set'), + } + return type(name, (Change,), attrs) + + + +class DocumentMeta(ModelBase): + "Metaclass for Document models." + def __new__(cls, name, bases, attrs): + model = super(DocumentMeta, cls).__new__(cls, name, bases, attrs) + if not model._meta.abstract: + # create a real Tag object and `stage' fk + model.tag_model = create_tag_model(model) + models.ForeignKey(model.tag_model, + null=True, blank=True).contribute_to_class(model, 'stage') + + # create real Change model and `head' fk + model.change_model = create_change_model(model) + models.ForeignKey(model.change_model, + null=True, blank=True, default=None, + help_text=_("This document's current head."), + editable=False).contribute_to_class(model, 'head') + + return model + + + class Document(models.Model): """ File in repository. """ + __metaclass__ = DocumentMeta + creator = models.ForeignKey(User, null=True, blank=True, editable=False, related_name="created_documents") - head = models.ForeignKey(Change, - null=True, blank=True, default=None, - help_text=_("This document's current head."), - editable=False) user = models.ForeignKey(User, null=True, blank=True) - stage = models.ForeignKey(Tag, null=True, blank=True) + + class Meta: + abstract = True def __unicode__(self): return u"{0}, HEAD: {1}".format(self.id, self.head_id) @@ -222,7 +262,7 @@ class Document(models.Model): else: parent = kwargs['parent'] if not isinstance(parent, Change): - parent = Change.objects.get(pk=kwargs['parent']) + parent = self.change_set.objects.get(pk=kwargs['parent']) if 'patch' not in kwargs: if 'text' not in kwargs: @@ -289,7 +329,7 @@ class Document(models.Model): if not isinstance(instance, Document): return if created: - instance.head = Change.objects.create( + instance.head = instance.change_model.objects.create( revision=-1, author=instance.creator, patch=Change.make_patch('', ''), diff --git a/apps/wiki/admin.py b/apps/wiki/admin.py index 9725d0bf..b742f70d 100644 --- a/apps/wiki/admin.py +++ b/apps/wiki/admin.py @@ -9,3 +9,5 @@ class BookAdmin(admin.ModelAdmin): admin.site.register(models.Book, BookAdmin) admin.site.register(models.Chunk) admin.site.register(models.Theme) + +admin.site.register(models.Chunk.tag_model) diff --git a/apps/wiki/fixtures/stages.json b/apps/wiki/fixtures/stages.json new file mode 100644 index 00000000..992ebc71 --- /dev/null +++ b/apps/wiki/fixtures/stages.json @@ -0,0 +1,83 @@ +[ + { + "pk": 1, + "model": "wiki.chunktag", + "fields": { + "ordering": 1, + "name": "Autokorekta", + "slug": "first_correction" + } + }, + { + "pk": 2, + "model": "wiki.chunktag", + "fields": { + "ordering": 2, + "name": "Tagowanie", + "slug": "tagging" + } + }, + { + "pk": 3, + "model": "wiki.chunktag", + "fields": { + "ordering": 3, + "name": "Korekta", + "slug": "proofreading" + } + }, + { + "pk": 4, + "model": "wiki.chunktag", + "fields": { + "ordering": 4, + "name": "Sprawdzenie przypis\u00f3w \u017ar\u00f3d\u0142a", + "slug": "annotation-proofreading" + } + }, + { + "pk": 5, + "model": "wiki.chunktag", + "fields": { + "ordering": 5, + "name": "Uwsp\u00f3\u0142cze\u015bnienie", + "slug": "modernisation" + } + }, + { + "pk": 6, + "model": "wiki.chunktag", + "fields": { + "ordering": 6, + "name": "Przypisy", + "slug": "annotations" + } + }, + { + "pk": 7, + "model": "wiki.chunktag", + "fields": { + "ordering": 7, + "name": "Motywy", + "slug": "themes" + } + }, + { + "pk": 8, + "model": "wiki.chunktag", + "fields": { + "ordering": 8, + "name": "Ostateczna redakcja literacka", + "slug": "editor-proofreading" + } + }, + { + "pk": 9, + "model": "wiki.chunktag", + "fields": { + "ordering": 9, + "name": "Ostateczna redakcja techniczna", + "slug": "technical-editor-proofreading" + } + } +] diff --git a/apps/wiki/forms.py b/apps/wiki/forms.py index e153f7e8..6b10909b 100644 --- a/apps/wiki/forms.py +++ b/apps/wiki/forms.py @@ -8,7 +8,6 @@ from django.db.models import Count from django import forms from django.utils.translation import ugettext_lazy as _ -from dvcs.models import Tag from wiki.constants import MASTERS from wiki.models import Book, Chunk @@ -18,7 +17,7 @@ class DocumentTagForm(forms.Form): """ id = forms.CharField(widget=forms.HiddenInput) - tag = forms.ModelChoiceField(queryset=Tag.objects.all()) + tag = forms.ModelChoiceField(queryset=Chunk.tag_model.objects.all()) revision = forms.IntegerField(widget=forms.HiddenInput) @@ -114,7 +113,7 @@ class DocumentTextSaveForm(forms.Form): ) stage_completed = forms.ModelChoiceField( - queryset=Tag.objects.all(), + queryset=Chunk.tag_model.objects.all(), required=False, label=_(u"Completed"), help_text=_(u"If you completed a life cycle stage, select it."), @@ -157,7 +156,7 @@ class ChunkForm(forms.ModelForm): Form used for editing a chunk. """ user = forms.ModelChoiceField(queryset= - User.objects.annotate(count=Count('document')). + User.objects.annotate(count=Count('chunk')). order_by('-count', 'last_name', 'first_name')) diff --git a/apps/wiki/helpers.py b/apps/wiki/helpers.py index fe4b3b86..253f1291 100644 --- a/apps/wiki/helpers.py +++ b/apps/wiki/helpers.py @@ -1,4 +1,5 @@ from django import http +from django.db.models import Count from django.utils import simplejson as json from django.utils.functional import Promise from datetime import datetime @@ -144,27 +145,50 @@ def active_tab(tab): return wrapper -class BookChunks(object): - """ - Yields the chunks of a book. - """ +class ChunksList(object): + def __init__(self, chunk_qs): + self.chunk_qs = chunk_qs.annotate( + book_length=Count('book__chunk')).select_related( + 'book', 'stage__name', + 'user') - def __init__(self, book): - self.book = book + self.book_ids = [x['book_id'] for x in chunk_qs.values('book_id')] + + def __getitem__(self, key): + if isinstance(key, slice): + return self.get_slice(key) + elif isinstance(key, int): + return self.get_slice(slice(key, key+1))[0] + else: + raise TypeError('Unsupported list index. Must be a slice or an int.') + + def __len__(self): + return len(self.book_ids) + + def get_slice(self, slice_): + book_ids = self.book_ids[slice_] + chunk_qs = self.chunk_qs.filter(book__in=book_ids) - @property - def chunks(self): - return self.book.chunk_set.all() + chunks_list = [] + book = None + for chunk in chunk_qs: + if chunk.book != book: + book = chunk.book + chunks_list.append(ChoiceChunks(book, [chunk], chunk.book_length)) + else: + chunks_list[-1].chunks.append(chunk) + return chunks_list -class ChoiceChunks(BookChunks): +class ChoiceChunks(object): """ Associates the given chunks iterable for a book. """ chunks = None - def __init__(self, book, chunks): + def __init__(self, book, chunks, book_length): self.book = book self.chunks = chunks + self.book_length = book_length diff --git a/apps/wiki/migrations/0003_add_dvcs.py b/apps/wiki/migrations/0003_add_dvcs.py new file mode 100644 index 00000000..a301abf9 --- /dev/null +++ b/apps/wiki/migrations/0003_add_dvcs.py @@ -0,0 +1,371 @@ +# encoding: utf-8 +import datetime +import os.path +import cPickle +import re +import urllib + +from django.conf import settings +from django.db import models +from mercurial import mdiff, hg, ui +from south.db import db +from south.v2 import SchemaMigration + +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): + """Unqotes URL + + # >>> urlunquote('Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84') + # u'Za\u017c\xf3\u0142\u0107_g\u0119\u015bl\u0105 ja\u017a\u0144' + """ + return unicode(urllib.unquote(url), 'utf-8', 'ignore') + + +def split_name(name): + parts = name.split('__') + return parts + + +def file_to_title(fname): + """ Returns a title-like version of a filename. """ + parts = (p.replace('_', ' ').title() for p in fname.split('__')) + return ' / '.join(parts) + + +def make_patch(src, dst): + if isinstance(src, unicode): + src = src.encode('utf-8') + if isinstance(dst, unicode): + dst = dst.encode('utf-8') + return cPickle.dumps(mdiff.textdiff(src, dst)) + + +def plain_text(text): + return re.sub(META_REGEX, '', text, 1) + + +def gallery(slug, text): + result = {} + + m = re.match(META_REGEX, text) + if m: + for line in m.group(1).split('\n'): + try: + k, v = line.split(':', 1) + result[k.strip()] = v.strip() + except ValueError: + continue + + gallery = result.get('gallery', slughifi(slug)) + + if gallery.startswith('/'): + gallery = os.path.basename(gallery) + + return gallery + + +def migrate_file_from_hg(orm, fname, entry): + fname = urlunquote(fname) + print fname + if fname.endswith('.xml'): + fname = fname[:-4] + title = file_to_title(fname) + fname = slughifi(fname) + # create all the needed objects + # what if it already exists? + book = orm.Book.objects.create( + title=title, + slug=fname) + chunk = orm.Chunk.objects.create( + book=book, + number=1, + slug='1') + head = orm['wiki.ChunkChange'].objects.create( + tree=chunk, + revision=-1, + patch=make_patch('', ''), + created_at=datetime.datetime.fromtimestamp(entry.filectx(0).date()[0]), + description='' + ) + chunk.head = head + try: + chunk.stage = orm['wiki.ChunkTag'].objects.order_by('ordering')[0] + except IndexError: + chunk.stage = None + old_data = '' + + maxrev = entry.filerev() + gallery_link = None + + for rev in xrange(maxrev + 1): + fctx = entry.filectx(rev) + data = fctx.data() + gallery_link = gallery(fname, data) + data = plain_text(data) + + # get tags from description + description = fctx.description().decode("utf-8", 'replace') + tags = STAGE_TAGS_RE.findall(description) + tags = [orm['wiki.ChunkTag'].objects.get(slug=slug.strip()) for slug in tags] + + if tags: + max_ordering = max(tags, key=lambda x: x.ordering).ordering + try: + chunk.stage = orm['wiki.ChunkTag'].objects.filter(ordering__gt=max_ordering).order_by('ordering')[0] + except IndexError: + chunk.stage = None + + 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['wiki.ChunkChange'].objects.create( + tree=chunk, + revision=rev + 1, + patch=make_patch(old_data, data), + created_at=datetime.datetime.fromtimestamp(fctx.date()[0]), + description=description, + author=author, + author_name=author_name, + author_email=author_email, + parent=chunk.head + ) + head.tags = tags + chunk.head = head + old_data = data + + chunk.save() + if gallery_link: + book.gallery = gallery_link + book.save() + + +def migrate_from_hg(orm): + try: + hg_path = settings.WIKI_REPOSITORY_PATH + except: + pass + + print 'migrate from', hg_path + repo = hg.repository(ui.ui(), hg_path) + tip = repo['tip'] + for fname in tip: + if fname.startswith('.'): + continue + migrate_file_from_hg(orm, fname, tip[fname]) + + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Book' + db.create_table('wiki_book', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=128, db_index=True)), + ('gallery', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='children', null=True, to=orm['wiki.Book'])), + ('parent_number', self.gf('django.db.models.fields.IntegerField')(db_index=True, null=True, blank=True)), + ('last_published', self.gf('django.db.models.fields.DateTimeField')(null=True)), + ('_list_html', self.gf('django.db.models.fields.TextField')(null=True)), + )) + db.send_create_signal('wiki', ['Book']) + + # Adding model 'Chunk' + db.create_table('wiki_chunk', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_documents', null=True, to=orm['auth.User'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('book', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.Book'])), + ('number', self.gf('django.db.models.fields.IntegerField')()), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)), + ('comment', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.ChunkTag'], null=True, blank=True)), + ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['wiki.ChunkChange'], null=True, blank=True)), + )) + db.send_create_signal('wiki', ['Chunk']) + + # Adding unique constraint on 'Chunk', fields ['book', 'number'] + db.create_unique('wiki_chunk', ['book_id', 'number']) + + # Adding unique constraint on 'Chunk', fields ['book', 'slug'] + db.create_unique('wiki_chunk', ['book_id', 'slug']) + + # Adding model 'ChunkTag' + db.create_table('wiki_chunktag', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), + ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=64, unique=True, null=True, blank=True)), + ('ordering', self.gf('django.db.models.fields.IntegerField')()), + )) + db.send_create_signal('wiki', ['ChunkTag']) + + # Adding model 'ChunkChange' + db.create_table('wiki_chunkchange', ( + ('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_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)), + ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['wiki.ChunkChange'])), + ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['wiki.ChunkChange'])), + ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)), + ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)), + ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('tree', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.Chunk'])), + )) + db.send_create_signal('wiki', ['ChunkChange']) + + # Adding unique constraint on 'ChunkChange', fields ['tree', 'revision'] + db.create_unique('wiki_chunkchange', ['tree_id', 'revision']) + + # Adding M2M table for field tags on 'ChunkChange' + db.create_table('wiki_chunkchange_tags', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('chunkchange', models.ForeignKey(orm['wiki.chunkchange'], null=False)), + ('chunktag', models.ForeignKey(orm['wiki.chunktag'], null=False)) + )) + db.create_unique('wiki_chunkchange_tags', ['chunkchange_id', 'chunktag_id']) + + if not db.dry_run: + from django.core.management import call_command + call_command("loaddata", "stages.json") + + migrate_from_hg(orm) + + def backwards(self, orm): + + # Removing unique constraint on 'ChunkChange', fields ['tree', 'revision'] + db.delete_unique('wiki_chunkchange', ['tree_id', 'revision']) + + # Removing unique constraint on 'Chunk', fields ['book', 'slug'] + db.delete_unique('wiki_chunk', ['book_id', 'slug']) + + # Removing unique constraint on 'Chunk', fields ['book', 'number'] + db.delete_unique('wiki_chunk', ['book_id', 'number']) + + # Deleting model 'Book' + db.delete_table('wiki_book') + + # Deleting model 'Chunk' + db.delete_table('wiki_chunk') + + # Deleting model 'ChunkTag' + db.delete_table('wiki_chunktag') + + # Deleting model 'ChunkChange' + db.delete_table('wiki_chunkchange') + + # Removing M2M table for field tags on 'ChunkChange' + db.delete_table('wiki_chunkchange_tags') + + + 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', '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'}), + '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'}) + }, + 'wiki.book': { + 'Meta': {'ordering': "['parent_number', 'title']", 'object_name': 'Book'}, + '_list_html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'gallery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_published': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['wiki.Book']"}), + 'parent_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'wiki.chunk': { + 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk'}, + 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Book']"}), + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', '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['wiki.ChunkChange']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'number': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.ChunkTag']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'wiki.chunkchange': { + 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ChunkChange'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", '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'}), + 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['wiki.ChunkChange']"}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['wiki.ChunkChange']"}), + '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['wiki.ChunkTag']", 'symmetrical': 'False'}), + 'tree': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Chunk']"}) + }, + 'wiki.chunktag': { + 'Meta': {'ordering': "['ordering']", 'object_name': 'ChunkTag'}, + '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'}) + }, + 'wiki.theme': { + 'Meta': {'ordering': "('name',)", 'object_name': 'Theme'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}) + } + } + + complete_apps = ['wiki'] 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 deleted file mode 100644 index deb649f9..00000000 --- a/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py +++ /dev/null @@ -1,323 +0,0 @@ -# encoding: utf-8 -import datetime -import os.path -import cPickle -import re -import urllib - -from django.conf import settings -from django.db import models -from mercurial import mdiff, hg, ui -from south.db import db -from south.v2 import SchemaMigration - -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): - """Unqotes URL - - # >>> urlunquote('Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84') - # u'Za\u017c\xf3\u0142\u0107_g\u0119\u015bl\u0105 ja\u017a\u0144' - """ - return unicode(urllib.unquote(url), 'utf-8', 'ignore') - - -def split_name(name): - parts = name.split('__') - return parts - - -def file_to_title(fname): - """ Returns a title-like version of a filename. """ - parts = (p.replace('_', ' ').title() for p in fname.split('__')) - return ' / '.join(parts) - - -def make_patch(src, dst): - if isinstance(src, unicode): - src = src.encode('utf-8') - if isinstance(dst, unicode): - dst = dst.encode('utf-8') - return cPickle.dumps(mdiff.textdiff(src, dst)) - - -def plain_text(text): - return re.sub(META_REGEX, '', text, 1) - - -def gallery(slug, text): - result = {} - - m = re.match(META_REGEX, text) - if m: - for line in m.group(1).split('\n'): - try: - k, v = line.split(':', 1) - result[k.strip()] = v.strip() - except ValueError: - continue - - gallery = result.get('gallery', slughifi(slug)) - - if gallery.startswith('/'): - gallery = os.path.basename(gallery) - - return gallery - - -def migrate_file_from_hg(orm, fname, entry): - fname = urlunquote(fname) - print fname - if fname.endswith('.xml'): - fname = fname[:-4] - title = file_to_title(fname) - fname = slughifi(fname) - # create all the needed objects - # what if it already exists? - book = orm.Book.objects.create( - title=title, - slug=fname) - chunk = orm.Chunk.objects.create( - book=book, - number=1, - slug='1') - head = orm['dvcs.Change'].objects.create( - tree=chunk, - revision=-1, - patch=make_patch('', ''), - created_at=datetime.datetime.fromtimestamp(entry.filectx(0).date()[0]), - description='' - ) - chunk.head = head - try: - chunk.stage = orm['dvcs.Tag'].objects.order_by('ordering')[0] - except IndexError: - chunk.stage = None - old_data = '' - - maxrev = entry.filerev() - gallery_link = None - - for rev in xrange(maxrev + 1): - fctx = entry.filectx(rev) - data = fctx.data() - gallery_link = gallery(fname, data) - data = plain_text(data) - - # get tags from description - description = fctx.description().decode("utf-8", 'replace') - tags = STAGE_TAGS_RE.findall(description) - tags = [orm['dvcs.Tag'].objects.get(slug=slug.strip()) for slug in tags] - - if tags: - max_ordering = max(tags, key=lambda x: x.ordering).ordering - try: - chunk.stage = orm['dvcs.Tag'].objects.filter(ordering__gt=max_ordering).order_by('ordering')[0] - except IndexError: - chunk.stage = None - - 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=author, - author_name=author_name, - author_email=author_email, - parent=chunk.head - ) - head.tags = tags - chunk.head = head - old_data = data - - chunk.save() - if gallery_link: - book.gallery = gallery_link - book.save() - - -def migrate_from_hg(orm): - try: - hg_path = settings.WIKI_REPOSITORY_PATH - except: - pass - - print 'migrate from', hg_path - repo = hg.repository(ui.ui(), hg_path) - tip = repo['tip'] - for fname in tip: - if fname.startswith('.'): - continue - migrate_file_from_hg(orm, fname, tip[fname]) - - -class Migration(SchemaMigration): - - depends_on = [ - ('dvcs', '0001_initial'), - ] - - def forwards(self, orm): - - # Adding model 'Book' - db.create_table('wiki_book', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('title', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=128, db_index=True)), - ('gallery', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), - ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='children', null=True, to=orm['wiki.Book'])), - ('parent_number', self.gf('django.db.models.fields.IntegerField')(db_index=True, null=True, blank=True)), - ('last_published', self.gf('django.db.models.fields.DateTimeField')(null=True)), - ('_list_html', self.gf('django.db.models.fields.TextField')(null=True)), - )) - db.send_create_signal('wiki', ['Book']) - - # Adding model 'Chunk' - db.create_table('wiki_chunk', ( - ('document_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['dvcs.Document'], unique=True, primary_key=True)), - ('book', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.Book'])), - ('number', self.gf('django.db.models.fields.IntegerField')()), - ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)), - ('comment', self.gf('django.db.models.fields.CharField')(max_length=255)), - )) - db.send_create_signal('wiki', ['Chunk']) - - # Adding unique constraint on 'Chunk', fields ['book', 'number'] - db.create_unique('wiki_chunk', ['book_id', 'number']) - - # Adding unique constraint on 'Chunk', fields ['book', 'slug'] - db.create_unique('wiki_chunk', ['book_id', 'slug']) - - if not db.dry_run: - migrate_from_hg(orm) - - def backwards(self, orm): - - # Removing unique constraint on 'Chunk', fields ['book', 'slug'] - db.delete_unique('wiki_chunk', ['book_id', 'slug']) - - # Removing unique constraint on 'Chunk', fields ['book', 'number'] - db.delete_unique('wiki_chunk', ['book_id', 'number']) - - # Deleting model 'Book' - db.delete_table('wiki_book') - - # Deleting model 'Chunk' - db.delete_table('wiki_chunk') - - - 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_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'}), - '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', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - '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'}) - }, - 'wiki.book': { - 'Meta': {'ordering': "['parent_number', 'title']", 'object_name': 'Book'}, - '_list_html': ('django.db.models.fields.TextField', [], {'null': 'True'}), - 'gallery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_published': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['wiki.Book']"}), - 'parent_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - 'wiki.chunk': { - 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk', '_ormbases': ['dvcs.Document']}, - 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Book']"}), - 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'document_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['dvcs.Document']", 'unique': 'True', 'primary_key': 'True'}), - 'number': ('django.db.models.fields.IntegerField', [], {}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}) - }, - 'wiki.theme': { - 'Meta': {'ordering': "('name',)", 'object_name': 'Theme'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}) - } - } - - complete_apps = ['wiki'] diff --git a/apps/wiki/models.py b/apps/wiki/models.py index 28fdab8b..d35b3c40 100644 --- a/apps/wiki/models.py +++ b/apps/wiki/models.py @@ -176,13 +176,12 @@ class Chunk(dvcs_models.Document): else: return cls.objects.get(book__slug=slug, slug=chunk) - def pretty_name(self): + def pretty_name(self, book_length=None): 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)) + if book_length > 1: + title += " (%d/%d)" % (self.number, book_length) return title def split(self, slug, comment='', creator=None): diff --git a/apps/wiki/templates/wiki/book_append_to.html b/apps/wiki/templates/wiki/book_append_to.html index 0350aa63..da6594da 100755 --- a/apps/wiki/templates/wiki/book_append_to.html +++ b/apps/wiki/templates/wiki/book_append_to.html @@ -3,6 +3,7 @@ {% block leftcolumn %}
+ {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/book_detail.html b/apps/wiki/templates/wiki/book_detail.html index 84d2097b..5ea0e3df 100755 --- a/apps/wiki/templates/wiki/book_detail.html +++ b/apps/wiki/templates/wiki/book_detail.html @@ -54,6 +54,7 @@ {% if need_fixing %} + {% csrf_token %} {% if choose_master %} {{ form.master }} {% endif %} @@ -89,7 +90,7 @@ -

+

{% else %} {% trans "This book cannot be published yet" %} {% endif %} diff --git a/apps/wiki/templates/wiki/book_edit.html b/apps/wiki/templates/wiki/book_edit.html index d5f527dc..8bc7ea7f 100755 --- a/apps/wiki/templates/wiki/book_edit.html +++ b/apps/wiki/templates/wiki/book_edit.html @@ -3,6 +3,7 @@ {% block leftcolumn %}
+ {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/chunk_add.html b/apps/wiki/templates/wiki/chunk_add.html index 2b8939e0..836c34d6 100755 --- a/apps/wiki/templates/wiki/chunk_add.html +++ b/apps/wiki/templates/wiki/chunk_add.html @@ -3,6 +3,7 @@ {% block leftcolumn %} + {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/chunk_edit.html b/apps/wiki/templates/wiki/chunk_edit.html index d5f527dc..8bc7ea7f 100755 --- a/apps/wiki/templates/wiki/chunk_edit.html +++ b/apps/wiki/templates/wiki/chunk_edit.html @@ -3,6 +3,7 @@ {% block leftcolumn %} + {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/document_list.html b/apps/wiki/templates/wiki/document_list.html index 2a0a5efa..434324ca 100644 --- a/apps/wiki/templates/wiki/document_list.html +++ b/apps/wiki/templates/wiki/document_list.html @@ -47,17 +47,19 @@ $(function() { {% endif %} {% for item in books %} {% with item.book as book %} - - {% ifequal book.chunk_set.count 1 %} + + {% ifequal item.book_length 1 %} + {% with item.chunks.0 as chunk %} [B] - [c] + [c] {{ book.title }} - ({{ book.0.stage }}) - {% if book.0.user %}{{ book.0.user.first_name }} {{ book.0.user.last_name }}{% endif %} + ({{ chunk.stage }}) + {% if chunk.user %}{{ chunk.user.first_name }} {{ chunk.user.last_name }}{% endif %} + {% endwith %} {% else %} [B] diff --git a/apps/wiki/templates/wiki/pubmark_dialog.html b/apps/wiki/templates/wiki/pubmark_dialog.html index 93a98563..a70a0c38 100755 --- a/apps/wiki/templates/wiki/pubmark_dialog.html +++ b/apps/wiki/templates/wiki/pubmark_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}
+ {% csrf_token %} {% for field in forms.pubmark.visible_fields %}

{{ field.label_tag }} {{ field }}

{{ field.help_text }}

diff --git a/apps/wiki/templates/wiki/revert_dialog.html b/apps/wiki/templates/wiki/revert_dialog.html index 7e5089f0..c2fc1553 100644 --- a/apps/wiki/templates/wiki/revert_dialog.html +++ b/apps/wiki/templates/wiki/revert_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}
+ {% csrf_token %}

{{ forms.text_revert.comment.label }}

{{ forms.text_revert.comment.help_text}} diff --git a/apps/wiki/templates/wiki/save_dialog.html b/apps/wiki/templates/wiki/save_dialog.html index b2f53bab..c34eb9ec 100644 --- a/apps/wiki/templates/wiki/save_dialog.html +++ b/apps/wiki/templates/wiki/save_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}

+ {% csrf_token %}

{{ forms.text_save.comment.label }}

{{ forms.text_save.comment.help_text}} diff --git a/apps/wiki/templates/wiki/tag_dialog.html b/apps/wiki/templates/wiki/tag_dialog.html index bc601cb9..aa4b2427 100644 --- a/apps/wiki/templates/wiki/tag_dialog.html +++ b/apps/wiki/templates/wiki/tag_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}

+ {% csrf_token %} {% for field in forms.add_tag.visible_fields %}

{{ field.label_tag }} {{ field }}

{{ field.help_text }}

diff --git a/apps/wiki/templatetags/wiki.py b/apps/wiki/templatetags/wiki.py index 337afa65..db2eca3e 100644 --- a/apps/wiki/templatetags/wiki.py +++ b/apps/wiki/templatetags/wiki.py @@ -1,13 +1,13 @@ from __future__ import absolute_import +from django.db.models import Count 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 +from wiki.models import Book, Chunk register = template.Library() @@ -63,11 +63,14 @@ class WallItem(object): def changes_wall(max_len): - qs = Change.objects.filter(revision__gt=-1).order_by('-created_at').select_related() + qs = Chunk.change_model.objects.filter(revision__gt=-1).order_by('-created_at') + qs = qs.defer('patch') + qs = qs.select_related('author', 'tree') + #qs = qs.annotate(book_length=Count('chunk__book__chunk')) qs = qs[:max_len] for item in qs: tag = 'stage' if item.tags.count() else 'change' - chunk = item.tree.chunk + chunk = item.tree w = WallItem(tag) w.title = chunk.pretty_name() w.summary = item.description diff --git a/apps/wiki/views.py b/apps/wiki/views.py index 7bff1a05..59ba9846 100644 --- a/apps/wiki/views.py +++ b/apps/wiki/views.py @@ -47,8 +47,12 @@ MAX_LAST_DOCS = 10 @active_tab('all') @never_cache def document_list(request): + chunks_list = helpers.ChunksList(Chunk.objects.order_by( + 'book__title', 'book', 'number')) + return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': [helpers.BookChunks(b) for b in Book.objects.all()], + 'books': chunks_list, + #'books': [helpers.BookChunks(b) for b in Book.objects.all().select_related()], 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -57,18 +61,11 @@ def document_list(request): @active_tab('unassigned') @never_cache def unassigned(request): - chunks = Chunk.objects.filter(user=None).order_by('book__title', 'book', 'number') - books = [] - book = None - for chunk in chunks: - if chunk.book != book: - book = chunk.book - books.append(helpers.ChoiceChunks(book, [chunk])) - else: - books[-1].chunks.append(chunk) + chunks_list = helpers.ChunksList(Chunk.objects.filter( + user=None).order_by('book__title', 'book__id', 'number')) return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': books, + 'books': chunks_list, 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -84,18 +81,11 @@ def user(request, username=None): else: user = get_object_or_404(User, username=username) - chunks = Chunk.objects.filter(user=user).order_by('book__title', 'number') - books = [] - book = None - for chunk in chunks: - if chunk.book != book: - book = chunk.book - books.append(helpers.ChoiceChunks(book, [chunk])) - else: - books[-1].chunks.append(chunk) + chunks_list = helpers.ChunksList(Chunk.objects.filter( + user=user).order_by('book__title', 'book', 'number')) return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': books, + 'books': chunks_list, 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -105,7 +95,7 @@ my = login_required(active_tab('my')(user)) @active_tab('users') def users(request): return direct_to_template(request, 'wiki/user_list.html', extra_context={ - 'users': User.objects.all().annotate(count=Count('document')).order_by( + 'users': User.objects.all().annotate(count=Count('chunk')).order_by( '-count', 'last_name', 'first_name'), }) diff --git a/redakcja/settings/common.py b/redakcja/settings/common.py index f55a877b..7c40abe5 100644 --- a/redakcja/settings/common.py +++ b/redakcja/settings/common.py @@ -61,13 +61,12 @@ SESSION_COOKIE_NAME = "redakcja_sessionid" # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - 'django.template.loaders.app_directories.load_template_source', -# 'django.template.loaders.eggs.load_template_source', + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', ) TEMPLATE_CONTEXT_PROCESSORS = ( - "django.core.context_processors.auth", + "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "redakcja.context_processors.settings", # this is instead of media