Basic changes, to display nicer names.
authorŁukasz Rekucki <lrekucki@gmail.com>
Tue, 1 Jun 2010 08:13:50 +0000 (10:13 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Tue, 1 Jun 2010 08:13:50 +0000 (10:13 +0200)
15 files changed:
apps/django_cas/backends.py
apps/wiki/helpers.py
apps/wiki/models.py
apps/wiki/templates/wiki/document_details_base.html
apps/wiki/templates/wiki/document_list.html
apps/wiki/templates/wiki/tabs/history_view.html
apps/wiki/templates/wiki/tabs/summary_view.html
apps/wiki/templates/wiki/tabs/summary_view_item.html
apps/wiki/urls.py
apps/wiki/views.py
lib/vstorage/__init__.py
logging.cfg.dev
redakcja/manage.py
redakcja/settings/common.py
redakcja/urls.py

index 328469a..d55c9db 100644 (file)
@@ -53,7 +53,7 @@ def _verify_cas2(ticket, service):
     except:
         import traceback
         traceback.print_exc()
-        print "****"
+        print "****", url
         print response
         print "****"
     finally:
index bc4b760..2cdb916 100644 (file)
@@ -58,3 +58,74 @@ def ajax_require_permission(permission):
             return view(request, *args, **kwargs)
         return authorized_view
     return decorator
+
+import collections
+
+def recursive_groupby(iterable):
+    """    
+#    >>> recursive_groupby([1,2,3,4,5])
+#    [1, 2, 3, 4, 5]
+    
+    >>> recursive_groupby([[1]])
+    [1]
+    
+    >>> recursive_groupby([('a', 1),('a', 2), 3, ('b', 4), 5])
+    ['a', [1, 2], 3, 'b', [4], 5]
+    
+    >>> recursive_groupby([('a', 'x', 1),('a', 'x', 2), ('a', 'x', 3)])
+    ['a', ['x', [1, 2, 3]]]
+   
+    """
+
+    def _generator(iterator):
+        group = None
+        grouper = None
+
+        for item in iterator:
+            if not isinstance(item, collections.Sequence):
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                yield item
+                continue
+            elif len(item) == 1:
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                yield item[0]
+                continue
+            elif not len(item):
+                continue
+
+            if grouper is None:
+                group = [item[1:]]
+                grouper = item[0]
+                continue
+
+            if grouper != item[0]:
+                if grouper is not None:
+                    yield grouper
+                    if len(group):
+                        yield recursive_groupby(group)
+                    group = None
+                    grouper = None
+                group = [item[1:]]
+                grouper = item[0]
+                continue
+
+            group.append(item[1:])
+
+        if grouper is not None:
+            yield grouper
+            if len(group):
+                yield recursive_groupby(group)
+            group = None
+            grouper = None
+
+    return list(_generator(iterable))
index a4dc794..d2b7460 100644 (file)
@@ -15,6 +15,25 @@ from django.http import Http404
 import logging
 logger = logging.getLogger("fnp.wiki")
 
+_PCHARS_DICT = dict(zip((ord(x) for x in u"ĄĆĘŁŃÓŚŻŹąćęłńóśżź "), u"ACELNOSZZacelnoszz_"))
+
+# I know this is barbaric, but I didn't find a better solution ;(
+def split_name(name):
+    parts = name.translate(_PCHARS_DICT).split('__')
+    logger.info("SPLIT %r -> %r", name, parts)
+    return parts
+
+def join_name(*parts, **kwargs):
+    name = u'__'.join(p.translate(_PCHARS_DICT) for p in parts)
+    logger.info("JOIN %r -> %r", parts, name)
+    return name
+
+def normalize_name(name):
+    """
+    >>> normalize_name("gąska".decode('utf-8'))
+    u'gaska'
+    """
+    return name.translate(_PCHARS_DICT).lower()
 
 STAGE_TAGS_RE = re.compile(r'^#stage-finished: (.*)$', re.MULTILINE)
 
@@ -37,7 +56,7 @@ class DocumentStorage(object):
         except DocumentNotFound:
             raise Http404
 
-    def put(self, document, author, comment, parent):
+    def put(self, document, author, comment, parent=None):
         self.vstorage.save_text(
                 title=document.name,
                 text=document.text,
@@ -47,15 +66,14 @@ class DocumentStorage(object):
 
         return document
 
-    def create_document(self, id, text, title=None):
-        if title is None:
-            title = id.title()
+    def create_document(self, text, name):
+        title = u', '.join(p.title for p in split_name(name))
 
         if text is None:
             text = u''
 
-        document = Document(self, name=id, text=text, title=title)
-        return self.put(document, u"<wiki>", u"Document created.", None)
+        document = Document(self, name=name, text=text, title=title)
+        return self.put(document, u"<wiki>", u"Document created.")
 
     def delete(self, name, author, comment):
         self.vstorage.delete_page(name, author, comment)
@@ -109,16 +127,11 @@ class Document(object):
             gallery = os.path.basename(gallery)
 
         result['gallery'] = gallery
-
-        if 'title' not in result:
-            result['title'] = self.name.title()
-
         return result
 
     def info(self):
         return self.storage.vstorage.page_meta(self.name, self.revision)
 
-
 def getstorage():
     return DocumentStorage(settings.REPOSITORY_PATH)
 
index 34106bb..28567e1 100644 (file)
@@ -30,7 +30,7 @@
 </div>
 
 <div id="header">
-    <h1><a href="{% url wiki.views.document_list %}">Platforma</a></h1>
+    <h1><a href="{% url wiki_document_list %}">Platforma</a></h1>
     <div id="tools">
         <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">
         {% trans "Help" %}</a>
index c2ade35..0ac2a35 100644 (file)
@@ -1,5 +1,7 @@
 {% extends "wiki/base.html" %}
+
 {% load i18n %}
+{% load wiki %}
 
 {% block extrabody %}
 {{ block.super }}
@@ -9,7 +11,7 @@ $(function() {
         event.preventDefault();
         var expr = new RegExp(slugify($('#file-list-filter').val()), 'i');
         $('#file-list tbody tr').hide().filter(function(index) {
-            return expr.test(slugify($('a', this).text()));
+            return expr.test(slugify( $('a', this).attr('data-id') ));
         }).show();
     }
 
@@ -29,9 +31,10 @@ $(function() {
                        </tr>
                </thead>
                <tbody>
-       {% for file in document_list %}
+       {% for doc in docs %}
             <tr>
-               <td colspan="3"><a target="_blank" href="{% url wiki.views.document_detail file|urlencode %}">{{ file }}</a></td>
+               <td colspan="3"><a target="_blank" data-id="{{doc}}" 
+                                       href="{% url wiki_editor doc %}">{{ doc|wiki_title }}</a></td>
                                <!-- placeholder </td> -->
                        </tr>
        {% endfor %}
@@ -43,10 +46,10 @@ $(function() {
 {% block rightcolumn %}
        <div id="last-edited-list">
                <h2>{% trans "Your last edited documents" %}</h2>
-               <ol>
-                       {% for   name, date in last_docs %}
-                       <li><a href="{% url wiki.views.document_detail name|urlencode %}"
-                               target="_blank">{{ name }}</a><br/><span class="date">({{ date|date:"H:i:s, d/m/Y" }})</span></li>
+           <ol>
+                       {% for name, date in last_docs %}
+                       <li><a href="{% url wiki_editor name %}"
+                               target="_blank">{{ name|wiki_title }}</a><br/><span class="date">({{ date|date:"H:i:s, d/m/Y" }})</span></li>
                        {% endfor %}
                </ol>
        </div>
index b55839c..5e385ab 100644 (file)
@@ -5,6 +5,7 @@
                <button type="button" id="tag-changeset-button">{% trans "Mark version" %}</button>
                <button id="open-preview-button"
                        data-basehref="{% url wiki_details_readonly document_name %}">{% trans "View version" %}</button>
+
        </div>
     <div id="history-view">
         <p class="message-box" style="display:none;"></p>
index 70ea2d9..c33baec 100644 (file)
@@ -1,4 +1,5 @@
 {% load i18n %}
+{% load wiki %}
 <div id="summary-view-editor" class="editor" style="display: none">
     <!-- <div class="toolbar">
     </div> -->
@@ -8,18 +9,18 @@
                <h2>
                        <label for="title">{% trans "Title" %}:</label>
                        <span data-ui-editable="true" data-edit-target="meta.displayTitle"
-                       >{{ document_meta.title }}</span>
+                       >{{ document.name|wiki_title }}</span>
                </h2>
                <p>
                        <label>{% trans "Document ID" %}:</label>
-                       <span>{{ document.name|urlencode }}</span>
+                       <span>{{ document.name }}</span>
                </p>
                <p>
                        <label>{% trans "Current version" %}:</label>
-                       {{ document_info.revision }} ({{document_info.last_update}})
+                       {{ document_info.revision }} ({{document_info.date}})
                <p>
                        <label>{% trans "Last edited by" %}:</label>
-                       {{document_info.last_comitter}}
+                       {{document_info.author}}
                </p>
                <p>
                        <label for="gallery">{% trans "Link to gallery" %}:</label>
@@ -29,4 +30,4 @@
 
                <p><button type="button" id="publish_button">{% trans "Publish" %}</button></p>
        </div>
-</div>
\ No newline at end of file
+</div>
index ce8d594..79c9f8f 100644 (file)
@@ -1,4 +1,5 @@
 {% load i18n %}
+{% load wiki %}
 <li id="SummaryPerspective" data-ui-related="summary-view-editor" data-ui-jsclass="SummaryPerspective">
-    <span>{{ document_meta.title }}</span>
+    <span>{{ document.name|wiki_title }}</span>
 </li>
index bfc799f..351ecbc 100644 (file)
@@ -1,29 +1,43 @@
+# -*- coding: utf-8
 from django.conf.urls.defaults import *
+from django.views.generic.simple import redirect_to
+from django.conf import settings
+
+
+PART = ur"""[ ĄĆĘŁŃÓŚŻŹąćęłńóśżź0-9\w_.-]+"""
 
 urlpatterns = patterns('wiki.views',
-    url(r'^$',
-        'document_list', name='wiki_doclist'),
+    url(r'^$', redirect_to, {'url': 'catalogue/'}),
+
+    url(r'^catalogue/$', 'document_list', name='wiki_document_list'),
+    url(r'^catalogue/([^/]+)/$', 'document_list'),
+    url(r'^catalogue/([^/]+)/([^/]+)/$', 'document_list'),
+    url(r'^catalogue/([^/]+)/([^/]+)/([^/]+)$', 'document_list'),
+
+    url(r'^(?P<name>%s)$' % PART,
+        'editor', name="wiki_editor"),
+
+    url(r'^(?P<name>[^/]+)/readonly$',
+        'editor_readonly', name="wiki_editor_readonly"),
 
     url(r'^create/(?P<name>[^/]+)',
-        'document_create_missing', name='wiki_create_missing'),
+        'create_missing', name='wiki_create_missing'),
+
+    url(r'^(?P<directory>[^/]+)/gallery$',
+        'gallery', name="wiki_gallery"),
 
-    url(r'^gallery/(?P<directory>[^/]+)$',
-        'document_gallery', name="wiki_gallery"),
     url(r'^(?P<name>[^/]+)/history$',
-        'document_history', name="wiki_history"),
+        'history', name="wiki_history"),
+
     url(r'^(?P<name>[^/]+)/text$',
-        'document_text', name="wiki_text"),
-    url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$',
-        'document_publish', name="wiki_publish"),
-    url(r'^(?P<name>[^/]+)/diff$',
-        'document_diff', name="wiki_diff"),
-    url(r'^(?P<name>[^/]+)/tags$',
-        'document_add_tag', name="wiki_add_tag"),
-    url(r'^(?P<name>[^/]+)/publish$', 'document_publish'),
+        'text', name="wiki_text"),
+
+    url(r'^(?P<name>[^/]+)/publish$', 'publish', name="wiki_publish"),
+    url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="wiki_publish"),
+
+    url(r'^(?P<name>[^/]+)/diff$', 'diff', name="wiki_diff"),
+    url(r'^(?P<name>[^/]+)/tags$', 'add_tag', name="wiki_add_tag"),
+
 
-    url(r'^(?P<name>[^/]+)/readonly$',
-        'document_detail_readonly', name="wiki_details_readonly"),
 
-    url(r'^(?P<name>[^/]+)$',
-        'document_detail', name="wiki_details"),
 )
index 1539baf..69c9836 100644 (file)
@@ -1,47 +1,64 @@
 import os
+import functools
+import logging
+logger = logging.getLogger("fnp.wiki")
 
 from django.conf import settings
 
 from django.views.generic.simple import direct_to_template
 from django.views.decorators.http import require_POST, require_GET
 from django.core.urlresolvers import reverse
-from wiki.helpers import JSONResponse, JSONFormInvalid, JSONServerError, ajax_require_permission
+from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
+                ajax_require_permission, recursive_groupby)
 from django import http
 
-from wiki.models import getstorage, DocumentNotFound
+from wiki.models import getstorage, DocumentNotFound, normalize_name, split_name, join_name
 from wiki.forms import DocumentTextSaveForm, DocumentTagForm, DocumentCreateForm
 from datetime import datetime
 from django.utils.encoding import smart_unicode
 from django.utils.translation import ugettext_lazy as _
 
-import wlapi
 
 #
 # Quick hack around caching problems, TODO: use ETags
 #
 from django.views.decorators.cache import never_cache
 
-import logging
-logger = logging.getLogger("fnp.peanut.api")
-
+import wlapi
 import nice_diff
 import operator
 
 MAX_LAST_DOCS = 10
 
 
+def normalized_name(view):
+
+    @functools.wraps(view)
+    def decorated(request, name, *args):
+        normalized = normalize_name(name)
+        logger.debug('View check %r -> %r', name, normalized)
+
+        if normalized != name:
+            return http.HttpResponseRedirect(
+                        reverse('wiki_' + view.__name__, kwargs={'name': normalized}))
+
+        return view(request, name, *args)
+
+    return decorated
+
+
 @never_cache
-def document_list(request, template_name='wiki/document_list.html'):
-    # TODO: find a way to cache "Storage All"
-    return direct_to_template(request, template_name, extra_context={
-        'document_list': getstorage().all(),
+def document_list(request):
+    return direct_to_template(request, 'wiki/document_list.html', extra_context={
+        'docs': getstorage().all(),
         'last_docs': sorted(request.session.get("wiki_last_docs", {}).items(),
                         key=operator.itemgetter(1), reverse=True),
     })
 
 
 @never_cache
-def document_detail(request, name, template_name='wiki/document_details.html'):
+@normalized_name
+def editor(request, name, template_name='wiki/document_details.html'):
     storage = getstorage()
 
     try:
@@ -71,7 +88,9 @@ def document_detail(request, name, template_name='wiki/document_details.html'):
 
 
 @require_GET
-def document_detail_readonly(request, name, template_name='wiki/document_details_readonly.html'):
+@normalized_name
+def editor_readonly(request, name, template_name='wiki/document_details_readonly.html'):
+    name = normalize_name(name)
     storage = getstorage()
 
     try:
@@ -97,7 +116,8 @@ def document_detail_readonly(request, name, template_name='wiki/document_details
     })
 
 
-def document_create_missing(request, name):
+@normalized_name
+def create_missing(request, name):
     storage = getstorage()
 
     if request.method == "POST":
@@ -122,7 +142,8 @@ def document_create_missing(request, name):
 
 
 @never_cache
-def document_text(request, name):
+@normalized_name
+def text(request, name):
     storage = getstorage()
 
     if request.method == 'POST':
@@ -174,7 +195,7 @@ def document_text(request, name):
 
 
 @never_cache
-def document_gallery(request, directory):
+def gallery(request, directory):
     try:
         base_url = ''.join((
                         smart_unicode(settings.MEDIA_URL),
@@ -201,7 +222,8 @@ def document_gallery(request, directory):
 
 
 @never_cache
-def document_diff(request, name):
+@normalized_name
+def diff(request, name):
     storage = getstorage()
 
     revA = int(request.GET.get('from', 0))
@@ -221,7 +243,8 @@ def document_diff(request, name):
 
 
 @never_cache
-def document_history(request, name):
+@normalized_name
+def history(request, name):
     storage = getstorage()
 
     # TODO: pagination
@@ -232,7 +255,8 @@ def document_history(request, name):
 
 @require_POST
 @ajax_require_permission('wiki.can_change_tags')
-def document_add_tag(request, name):
+def add_tag(request, name):
+    name = normalize_name(name)
     storage = getstorage()
 
     form = DocumentTagForm(request.POST, prefix="addtag")
@@ -248,7 +272,9 @@ def document_add_tag(request, name):
 
 @require_POST
 @ajax_require_permission('wiki.can_publish')
-def document_publish(request, name):
+def publish(request, name):
+    name = normalize_name(name)
+
     storage = getstorage()
     document = storage.get_by_tag(name, "ready_to_publish")
 
index b4acaf3..aeb7338 100644 (file)
@@ -27,18 +27,18 @@ def urlquote(url, safe='/'):
     """Quotes URL
 
     >>> urlquote(u'Za\u017c\xf3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144')
-    'Za%C5%BC%C3%B3%C5%82%C4%87_g%C4%99%C5%9Bl%C4%85_ja%C5%BA%C5%84'
+    'Za%C5%BC%C3%B3%C5%82%C4%87%20g%C4%99%C5%9Bl%C4%85%20ja%C5%BA%C5%84'
     """
-    return urllib.quote(url.replace(' ', '_').encode('utf-8', 'ignore'), safe)
+    return urllib.quote(url.encode('utf-8', 'ignore'), safe)
 
 
 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'
+    # u'Za\u017c\xf3\u0142\u0107_g\u0119\u015bl\u0105 ja\u017a\u0144'
     """
-    return unicode(urllib.unquote(url), 'utf-8', 'ignore').replace('_', ' ')
+    return unicode(urllib.unquote(url), 'utf-8', 'ignore')
 
 
 def find_repo_path(path):
@@ -151,12 +151,12 @@ class VersionedStorage(object):
     def _file_path(self, title):
         return os.path.join(self.path, urlquote(title, safe=''))
 
-    def _title_to_file(self, title):
-        return os.path.join(self.repo_prefix, urlquote(title, safe=''))
+    def _title_to_file(self, title, type=".xml"):
+        return os.path.join(self.repo_prefix, urlquote(title, safe='')) + type
 
     def _file_to_title(self, filename):
         assert filename.startswith(self.repo_prefix)
-        name = filename[len(self.repo_prefix):].strip('/')
+        name = filename[len(self.repo_prefix):].strip('/').split('.', 1)[0]
         return urlunquote(name)
 
     def __contains__(self, title):
@@ -411,10 +411,12 @@ class VersionedStorage(object):
                         rev = -1
                     yield title, rev, date, author, comment
 
-    def all_pages(self):
+    def all_pages(self, type=''):
         tip = self.repo['tip']
         """Iterate over the titles of all pages in the wiki."""
-        return [urlunquote(filename) for filename in tip]
+        return [self._file_to_title(filename) for filename in tip
+                  if not filename.startswith('.')
+                    and filename.endswith(type) ]
 
     def changed_since(self, rev):
         """Return all pages that changed since specified repository revision."""
index 9bfa56c..23a7833 100644 (file)
@@ -23,7 +23,7 @@ datefmt=
 class=logging.Formatter
 
 [handler_console]
-class=StreamHandler
+class=FileHandler
 level=DEBUG
 formatter=default
-args=(sys.stderr, ) 
\ No newline at end of file
+args=('redakcja.dev.log', ) 
index 1fc25dd..4c11842 100755 (executable)
@@ -9,10 +9,15 @@ except ImportError:
 
 if __name__ == "__main__":
     # Append lib and apps directories to PYTHONPATH
-    from os import path
+    import os
     import sys
 
-    PROJECT_ROOT = path.realpath(path.dirname(__file__))
-    sys.path += [PROJECT_ROOT + '/../apps', PROJECT_ROOT + '/../lib']
+    PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__))
+    sys.path += [os.path.realpath(os.path.join(*x)) for x in (
+        (PROJECT_ROOT, '..', 'apps'),
+        (PROJECT_ROOT, '..', 'lib')
+    )]
+
+
 
     execute_manager(settings)
index 0a3b376..379f5b5 100644 (file)
@@ -140,3 +140,17 @@ WL_API_CONFIG = {
 }
 
 # Import localsettings file, which may override settings defined here
+
+try:
+    import logging
+    if os.path.isfile(LOGGING_CONFIG_FILE):
+        import logging.config
+        logging.config.fileConfig(LOGGING_CONFIG_FILE)
+    else:
+        import sys
+        logging.basicConfig(stream=sys.stderr)
+except NameError:
+    print "No logging"
+    pass
+except ImportError as exc:
+    raise
index f8538fa..191bcc2 100644 (file)
@@ -4,6 +4,8 @@ from django.conf.urls.defaults import *
 from django.contrib import admin
 from django.conf import settings
 
+import wiki.urls
+
 admin.autodiscover()
 
 urlpatterns = patterns('',
@@ -26,4 +28,7 @@ urlpatterns = patterns('',
         {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
     url(r'^%s(?P<path>.+)$' % settings.STATIC_URL[1:], 'django.views.static.serve',
         {'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
+    (r'^documents/', include(wiki.urls)),
+    url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/documents/'}),
+
 )