from django.contrib.admin import site
-from dvcs.models import Document, Change
+from dvcs.models import Document, Change, Tag
+site.register(Tag)
site.register(Document)
site.register(Change)
--- /dev/null
+# 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 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'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Tag'
+ db.delete_table('dvcs_tag')
+
+ # Removing M2M table for field tags on 'Change'
+ db.delete_table('dvcs_change_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', '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'}),
+ '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'})
+ },
+ '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']
from mercurial import mdiff, simplemerge
import pickle
+
+class Tag(models.Model):
+ """
+ a tag (e.g. document stage) which can be applied to a change
+ """
+
+ name = models.CharField(_('name'), max_length=64)
+ slug = models.SlugField(_('slug'), unique=True, max_length=64,
+ null=True, blank=True)
+ ordering = models.IntegerField(_('ordering'))
+
+ _object_cache = {}
+
+ class Meta:
+ ordering = ['ordering']
+
+ def __unicode__(self):
+ return self.name
+
+ @classmethod
+ def get(cls, slug):
+ if slug in cls._object_cache:
+ return cls._object_cache[slug]
+ else:
+ obj = cls.objects.get(slug=slug)
+ cls._object_cache[slug] = obj
+ return obj
+
+ @staticmethod
+ def listener_changed(sender, instance, **kwargs):
+ sender._object_cache = {}
+
+models.signals.pre_save.connect(Tag.listener_changed, sender=Tag)
+
+
class Change(models.Model):
"""
Single document change related to previous change. The "parent"
created_at = models.DateTimeField(editable=False, db_index=True,
default=datetime.now)
+ tags = models.ManyToManyField(Tag)
+
class Meta:
ordering = ('created_at',)
unique_together = ['tree', 'revision']
text = change.apply_to(text)
return text
- def make_child(self, patch, description, author=None, author_desc=None):
- return self.children.create(patch=patch,
+ def make_child(self, patch, description, author=None,
+ author_desc=None, tags=None):
+ ch = self.children.create(patch=patch,
tree=self.tree, author=author,
author_desc=author_desc,
description=description)
+ if tags is not None:
+ ch.tags = tags
+ return ch
def make_merge_child(self, patch, description, author=None,
- author_desc=None):
- return self.merge_children.create(patch=patch,
+ author_desc=None, tags=None):
+ ch = self.merge_children.create(patch=patch,
tree=self.tree, author=author,
author_desc=author_desc,
- description=description)
+ description=description,
+ tags=tags)
+ if tags is not None:
+ ch.tags = tags
+ return ch
def apply_to(self, text):
return mdiff.patch(text, pickle.loads(self.patch.encode('ascii')))
author = kwargs.get('author', None)
author_desc = kwargs.get('author_desc', None)
+ tags = kwargs.get('tags', [])
old_head = self.head
if parent != old_head:
change = parent.make_merge_child(patch, author=author,
author_desc=author_desc,
- description=kwargs.get('description', ''))
+ 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)
else:
self.head = parent.make_child(patch, author=author,
author_desc=author_desc,
- description=kwargs.get('description', ''))
+ description=kwargs.get('description', ''),
+ tags=tags)
self.save()
return self.head
else:
return self.head
+ def last_tagged(self, tag):
+ changes = tag.change_set.filter(tree=self).order_by('-created_at')[:1]
+ if changes.count():
+ return changes[0]
+ else:
+ return None
+
@staticmethod
def listener_initial_commit(sender, instance, created, **kwargs):
# run for Document and its subclasses
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django import forms
-from wiki.constants import DOCUMENT_TAGS, DOCUMENT_STAGES
from wiki.models import Book
from django.utils.translation import ugettext_lazy as _
+from dvcs.models import Tag
class DocumentTagForm(forms.Form):
"""
"""
id = forms.CharField(widget=forms.HiddenInput)
- tag = forms.ChoiceField(choices=DOCUMENT_TAGS)
+ tag = forms.ModelChoiceField(queryset=Tag.objects.all())
revision = forms.IntegerField(widget=forms.HiddenInput)
help_text=_(u"Describe changes you made."),
)
- stage_completed = forms.ChoiceField(
- choices=DOCUMENT_STAGES,
+ stage_completed = forms.ModelChoiceField(
+ queryset=Tag.objects.all(),
required=False,
label=_(u"Completed"),
help_text=_(u"If you completed a life cycle stage, select it."),
--- /dev/null
+# 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 'Book._list_html'
+ db.add_column('wiki_book', '_list_html', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Book._list_html'
+ db.delete_column('wiki_book', '_list_html')
+
+
+ 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'}),
+ 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+ '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'})
+ },
+ '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'}),
+ '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']
from django.core.urlresolvers import reverse
from django.db import models
+from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
+from django.template.loader import render_to_string
from dvcs import models as dvcs_models
parent = models.ForeignKey('self', null=True, blank=True, verbose_name=_('parent'), related_name="children")
parent_number = models.IntegerField(_('parent number'), null=True, blank=True, db_index=True)
+ _list_html = models.TextField(editable=False, null=True)
+
+ class NoTextError(BaseException):
+ pass
+
class Meta:
ordering = ['parent_number', 'title']
verbose_name = _('book')
def __unicode__(self):
return self.title
+ def save(self, reset_list_html=True, *args, **kwargs):
+ if reset_list_html:
+ self._list_html = None
+ return super(Book, self).save(*args, **kwargs)
+
@classmethod
def create(cls, creator=None, text=u'', *args, **kwargs):
"""
def __len__(self):
return self.chunk_set.count()
+ def list_html(self):
+ if self._list_html is None:
+ print 'rendering', self.title
+ self._list_html = render_to_string('wiki/document_list_item.html',
+ {'book': self})
+ self.save(reset_list_html=False)
+ return mark_safe(self._list_html)
+
@staticmethod
def trim(text, trim_begin=True, trim_end=True):
"""
text = RE_TRIM_END.split(text, maxsplit=1)[0]
return text
- def materialize(self):
+ @staticmethod
+ def publish_tag():
+ return dvcs_models.Tag.get('publish')
+
+ def materialize(self, tag=None):
"""
Get full text of the document compiled from chunks.
Takes the current versions of all texts for now, but it should
First non-empty text's beginning isn't trimmed,
and last non-empty text's end isn't trimmed.
"""
+ if tag:
+ changes = [chunk.last_tagged(tag) for chunk in self]
+ else:
+ changes = [chunk.head for chunk in self]
+ if None in changes:
+ raise self.NoTextError('Some chunks have no available text.')
texts = []
trim_begin = False
text = ''
- for chunk in self:
+ for chunk in changes:
next_text = chunk.materialize()
if not next_text:
continue
texts.append(self.trim(text, trim_begin=trim_begin, trim_end=False))
return "".join(texts)
+ def publishable(self):
+ if not len(self):
+ return False
+ for chunk in self:
+ if not chunk.publishable():
+ return False
+ return True
+
@staticmethod
def listener_create(sender, instance, created, **kwargs):
if created:
return "%s, %s (%d/%d)" % (self.book.title, self.comment,
self.number, len(self.book))
+ def publishable(self):
+ return self.last_tagged(Book.publish_tag())
+ @staticmethod
+ def listener_saved(sender, instance, created, **kwargs):
+ if instance.book:
+ # save book so that its _list_html is reset
+ instance.book.save()
-
-'''
-from wiki import settings, constants
-from slughifi import slughifi
-
-from django.http import Http404
-
-
-
-
-class Document(object):
-
- def add_tag(self, tag, revision, author):
- """ Add document specific tag """
- logger.debug("Adding tag %s to doc %s version %d", tag, self.name, revision)
- self.storage.vstorage.add_page_tag(self.name, revision, tag, user=author)
-
- @property
- def plain_text(self):
- return re.sub(self.META_REGEX, '', self.text, 1)
-
- def meta(self):
- result = {}
-
- m = re.match(self.META_REGEX, self.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(self.name.replace(' ', '_')))
-
- if gallery.startswith('/'):
- gallery = os.path.basename(gallery)
-
- result['gallery'] = gallery
- return result
-
- def info(self):
- return self.storage.vstorage.page_meta(self.name, self.revision)
-
+models.signals.post_save.connect(Chunk.listener_saved, sender=Chunk)
-'''
class Theme(models.Model):
name = models.CharField(_('name'), max_length=50, unique=True)
</thead>
<tbody>
{% for book in books %}
- <tr>
- <td colspan="3">
- <a target="_blank" data-id="{{ book.slug }}"
- href="{% url wiki_book book.slug %}">[?]</a>
- {% ifequal book.chunk_set.count 1 %}
- <a target="_blank" data-id="{{ book.slug }}"
- href="{% url wiki_editor book.slug %}">
- {{ book.title }}</a>
- {% else %}
- {{ book.title }}
- <div class="chunk-list">
- {% for chunk in book %}
- <a target="_blank" data-id="{{ book.slug }}"
- href="{{ chunk.get_absolute_url }}">
- <span class='chunkno'>{{ forloop.counter }}.</span>
- {{ chunk.comment }}</a><br/>
- {% endfor %}
- </div>
- {% endifequal %}
- </td>
- <!-- placeholder </td> -->
- </tr>
+ {{ book.list_html }}
{% endfor %}
</tbody>
</table>
--- /dev/null
+<tr>
+ <td colspan="3">
+ <a target="_blank" data-id="{{ book.slug }}"
+ href="{% url wiki_book book.slug %}">[?]</a>
+ {% ifequal book.chunk_set.count 1 %}
+ <a target="_blank" data-id="{{ book.slug }}"
+ href="{% url wiki_editor book.slug %}">
+ {{ book.title }}</a>
+ {% else %}
+ {{ book.title }}
+ <div class="chunk-list">
+ {% for chunk in book %}
+ <a target="_blank" data-id="{{ book.slug }}"
+ href="{{ chunk.get_absolute_url }}">
+ <span class='chunkno'>{{ forloop.counter }}.</span>
+ {{ chunk.comment }}</a><br/>
+ {% endfor %}
+ </div>
+ {% endifequal %}
+ </td>
+</tr>
#url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="wiki_publish"),
url(r'^diff/(?P<slug>[^/]+)/(?:(?P<chunk>[^/]+)/)?$', 'diff', name="wiki_diff"),
- #url(r'^(?P<name>[^/]+)/tags$', 'add_tag', name="wiki_add_tag"),
+ url(r'^tag/(?P<slug>[^/]+)/(?:(?P<chunk>[^/]+)/)?$', 'add_tag', name="wiki_add_tag"),
url(r'^book/(?P<slug>[^/]+)/$', 'book', name="wiki_book"),
url(r'^book/(?P<slug>[^/]+)/xml$', 'book_xml', name="wiki_book_xml"),
from django.http import Http404
from wiki.models import Book, Chunk, Theme
-from wiki.forms import DocumentTextSaveForm, DocumentTextRevertForm, DocumentTagForm, DocumentCreateForm, DocumentsUploadForm
+from wiki.forms import (DocumentTextSaveForm, DocumentTextRevertForm, DocumentTagForm, DocumentCreateForm, DocumentsUploadForm,
+ ChunkFormSet)
from datetime import datetime
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
if request.method == 'POST':
form = DocumentTextSaveForm(request.POST, prefix="textsave")
if form.is_valid():
- # TODO:
- # - stage completion should be stored (as a relation)
-
if request.user.is_authenticated():
author = request.user
else:
text = form.cleaned_data['text']
parent_revision = form.cleaned_data['parent_revision']
parent = doc.at_revision(parent_revision)
+ stage = form.cleaned_data['stage_completed']
+ tags = [stage] if stage else []
doc.commit(author=author,
text=text,
parent=parent,
description=form.cleaned_data['comment'],
+ tags=tags,
)
revision = doc.revision()
return JSONResponse({
@never_cache
def book_xml(request, slug):
- xml = get_object_or_404(Book, slug=slug).materialize()
-
+ xml = get_object_or_404(Book, slug=slug).materialize(Book.publish_tag())
+
response = http.HttpResponse(xml, content_type='application/xml', mimetype='application/wl+xml')
response['Content-Disposition'] = 'attachment; filename=%s.xml' % slug
return response
@never_cache
def book_txt(request, slug):
- xml = get_object_or_404(Book, slug=slug).materialize()
+ xml = get_object_or_404(Book, slug=slug).materialize(Book.publish_tag())
output = StringIO()
# errors?
librarian.text.transform(StringIO(xml), output)
@never_cache
def book_html(request, slug):
- xml = get_object_or_404(Book, slug=slug).materialize()
+ xml = get_object_or_404(Book, slug=slug).materialize(Book.publish_tag())
output = StringIO()
# errors?
librarian.html.transform(StringIO(xml), output, parse_dublincore=False,
"description": change.description,
"author": change.author_str(),
"date": change.created_at,
- "tag": [],
+ "tag": ',\n'.join(unicode(tag) for tag in change.tags.all()),
})
return JSONResponse(changes)
})
-
-"""
-import wlapi
-
-
@require_POST
@ajax_require_permission('wiki.can_change_tags')
-def add_tag(request, name):
- name = normalize_name(name)
- storage = getstorage()
-
+def add_tag(request, slug, chunk=None):
form = DocumentTagForm(request.POST, prefix="addtag")
if form.is_valid():
- doc = storage.get_or_404(form.cleaned_data['id'])
- doc.add_tag(tag=form.cleaned_data['tag'],
- revision=form.cleaned_data['revision'],
- author=request.user.username)
+ try:
+ doc = Chunk.get(slug, chunk)
+ except (Chunk.MultipleObjectsReturned, Chunk.DoesNotExist):
+ raise Http404
+
+ tag = form.cleaned_data['tag']
+ revision = revision=form.cleaned_data['revision']
+ doc.at_revision(revision).tags.add(tag)
return JSONResponse({"message": _("Tag added")})
else:
return JSONFormInvalid(form)
+"""
+import wlapi
+
+
@require_POST
@ajax_require_permission('wiki.can_publish')
def publish(request, name):
stub: $stub,
data: this,
filters: {
- tag: function(value) {
- return tags.filter("*[value='"+value+"']").text();
- }
+// tag: function(value) {
+// return tags.filter("*[value='"+value+"']").text();
+// }
// description: function(value) {
// return value.replace('\n', ');
// }
return base_path + "/rev/" + arguments[1] + '/';
if (vname == "ajax_document_addtag")
- return base_path + "/tags/" + arguments[1] + '/';
+ return base_path + "/tag/" + arguments[1] + '/';
if (vname == "ajax_publish")
return base_path + "/publish/" + arguments[1] + '/';