Commits

sirex committed b251fa6

Big refactoring.

  • Participants
  • Parent commits 210ac27

Comments (0)

Files changed (12)

sboard/categories/forms.py

-from django import forms
-
-from couchdbkit.ext.django.forms import DocumentForm
-
-from .models import Category
-
-
-class CategoryForm(DocumentForm):
-    title = forms.CharField()
-    parent = forms.SlugField(required=False)
-    body = forms.CharField(widget=forms.Textarea, required=False)
-
-    class Meta:
-        document = Category
-        properties = ('title', 'parent', 'body')

sboard/categories/nodes.py

 from sboard.models import couch
 from sboard.nodes import CreateView
 
-from .forms import CategoryForm
 from .interfaces import ICategory
 
 
 class CategoryCreateView(CreateView):
     adapts(object, ICategory)
 
-    form = CategoryForm
-
     listing = True
 
     def get_node_list(self):

sboard/debugtoolbar.py

 
 from couchdbkit.client import ViewResults
 
-from .factory import INodeFactory
-from .interfaces import INodeView
 from .models import getRootNode
-from .views import get_node
+from .models import get_node_by_slug
+from .views import get_node_view
 from .views import node as node_view
 
 
-def get_node_view(node, slug=None, action='', name=''):
-    if name:
-        factory = getUtility(INodeFactory, name)
-        return getMultiAdapter((node, factory), INodeView, action)
-    else:
-        return getAdapter(node, INodeView, action)
-
-
 class NodeDebugPanel(DebugPanel):
     """
     A panel to display request variables (POST/GET, session, cookies).
 
     def process_view(self, request, view_func, view_args, view_kwargs):
         if view_func is node_view:
-            node = get_node(request, *view_args, **view_kwargs)
+            slug = view_kwargs.get('slug', None)
+            if slug is None and view_args:
+                slug = view_args[0]
+            node = get_node_by_slug(slug)
 
             if node is None:
                 view = None
                 node = getRootNode()
                 view = get_node_view(node, action='list')
             else:
-                view = get_node_view(node, *view_args, **view_kwargs)
+                action = view_kwargs.get('action', '')
+                name = view_kwargs.get('name', '')
+                view = get_node_view(node, action, name)
 
             context = {
                 'view': view,
+import re
+
 from django import forms
 from django.core.validators import EMPTY_VALUES
+from django.core.validators import RegexValidator
+from django.utils.translation import ugettext_lazy as _
 
-from couchdbkit.exceptions import ResourceNotFound
+from couchdbkit.client import ViewResults
 
-from .models import couch
+from .models import get_node_by_slug
+from .urls import slug
+
+slug_re = re.compile(r'^%s$' % slug)
+validate_slug = RegexValidator(slug_re,
+        _(u"Enter a valid 'slug' consisting of letters, numbers, underscores "
+          u"or hyphens."), 'invalid')
 
 
 class NodeField(forms.SlugField):
+    default_validators = [validate_slug]
+
     def clean(self, value):
         value = super(NodeField, self).clean(value)
         if value in EMPTY_VALUES:
             return None
-        try:
-            return couch.get(value)
-        except ResourceNotFound:
-            raise forms.ValidationError("'%s' does not exists." % value)
+
+        node = get_node_by_slug(value)
+        if node is None:
+            raise forms.ValidationError(_("'%s' does not exists.") % value)
+        elif isinstance(node, ViewResults):
+            raise forms.ValidationError(
+                    _("More than one node matched '%s' slug.") % value)
+        else:
+            return node
 from django import forms
 
-from couchdbkit.ext.django.forms import DocumentForm
+from .fields import NodeField
 
-from .fields import NodeField
-from .models import Node, Comment, Tag
 
+class BaseNodeForm(forms.Form):
+    def __init__(self, node, *args, **kwargs):
+        self.node = node
+        if self.node:
+            initial = self.get_initial_values()
+            if 'initial' in kwargs:
+                initial = initial.update(kwargs['initial'])
+            kwargs['initial'] = initial
+        super(BaseNodeForm, self).__init__(*args, **kwargs)
 
-class NodeForm(DocumentForm):
+    def get_initial_values(self):
+        initial = dict(self.node._doc)
+        initial['body'] = self.node.get_body()
+        return initial
+
+
+class NodeForm(BaseNodeForm):
     title = forms.CharField()
     parent = NodeField(required=False)
-    body = forms.CharField(widget=forms.Textarea)
+    summary = forms.CharField(widget=forms.Textarea, required=False)
+    body = forms.CharField(widget=forms.Textarea, required=False)
 
-    class Meta:
-        document = Node
-        properties = ('title', 'parent', 'body')
 
-
-class TagForm(forms.Form):
-    tag = forms.SlugField()
-
-    def __init__(self, node, *args, **kwargs):
-        super(TagForm, self).__init__(*args, **kwargs)
-        self.node = node
+class TagForm(BaseNodeForm):
+    tag = NodeField()
 
     def clean_tag(self):
         tag = self.cleaned_data.get('tag')
         return tag
 
 
-class TagNodeForm(DocumentForm):
+class TagNodeForm(BaseNodeForm):
     title = forms.CharField(required=True)
 
-    class Meta:
-        document = Tag
-        properties = ('title',)
 
-
-class CommentForm(DocumentForm):
+class CommentForm(BaseNodeForm):
     body = forms.CharField(required=True, widget=forms.Textarea)
-
-    class Meta:
-        document = Comment
-        properties = ('body',)
 from django.utils.translation import ugettext_lazy as _
 
 from couchdbkit.exceptions import BadValueError 
+from couchdbkit.exceptions import MultipleResultsFound
+from couchdbkit.exceptions import NoResultFound
 from couchdbkit.exceptions import ResourceNotFound
 from couchdbkit.ext.django import schema
 from couchdbkit.ext.django.loading import couchdbkit_handler
     return UniqueKey.objects.create().key
 
 
+def parse_node_slug(slug):
+    if slug and '+' in slug:
+        return slug.split('+')
+    else:
+        return slug, None
+
+
+def get_node_by_slug(slug=None):
+    """Returns Node instance, None or ViewResults instance."""
+    slug, key = parse_node_slug(slug)
+    if key:
+        try:
+            return couch.get(key)
+        except NoResultFound:
+            return None
+
+    if slug is None or slug == '~':
+        return getRootNode()
+
+    query = couch.by_slug(key=slug, limit=20)
+    try:
+        return query.one(except_all=True)
+    except MultipleResultsFound:
+        return query
+    except NoResultFound:
+        return None
+
+
 class NodeRef(object):
     def __init__(self):
         self._id = None
         permissions = self.get_permissions()
         return permissions.can(self.request, action, factory.name)
 
-    def get_create_links(self):
-        links = []
-        for name, factory in getNodeFactories():
-            if self.can('create', factory):
-                link = self.node.permalink('create', name)
-                links.append((link, name))
-        return links
-
-    def get_convert_to_links(self):
-        links = []
-        for name, factory in getNodeFactories():
-            if self.can('create', factory):
-                link = self.node.permalink('convert', name)
-                links.append((link, name))
-        return links
-
     def get_node_list(self):
         if self.node:
             key = self.node._id
         else:
             return couch.all_nodes(descending=True, limit=50)
 
-    def list_actions(self):
-        actions = []
-        if self.node and self.can('update'):
-            actions.append((self.node.permalink('update'), _('Edit'), None))
+    def get_form(self, *args, **kwargs):
+        return self.form(self.node, *args, **kwargs)
 
-        create_links = self.get_create_links()
-        if create_links:
-            actions.append((None, _('Create new entry'), create_links))
+    def form_save(self, form, node=None):
+        create = node is None
+        data = form.cleaned_data
 
-        return actions
+        if node is None:
+            node = self.factory()
+            node._id = node.get_new_id()
 
-    def details_actions(self):
-        actions = []
-        if self.node:
-            link = self.node.permalink('update')
-            actions.append((link, _('Edit'), None))
+        parent = data.pop('parent', None) or self.node
 
-        actions.append((None, _('Convert to'),
-                       self.get_convert_to_links()))
+        for key, val in data.items():
+            setattr(node, key, val)
 
-        return actions
+        node.slug = slugify(node.title)
 
-    def get_form(self, *args, **kwargs):
-        if self.node and not self.node.is_root():
-            kwargs['initial'] = {'parent': self.node._id}
-        return self.form(*args, **kwargs)
-
-    def form_save(self, form, create):
-        node = form.save(commit=False)
-        if create:
-            node._id = node.get_new_id()
-        else:
-            # TODO: create history entry
-            pass
-        node.slug = slugify(node.title)
         # XXX: actualy parent is always known from self.node, some here more
         # strict checking must be implemented. Only privileged users should be
         # able to change node parent, since this is expensive operation...
-        parent = form.cleaned_data.get('parent')
         if parent:
-            node.parent = parent._id
+            node.parent = parent
             node.set_parents(parent)
+
         if self.node:
             self.node.before_child_save(form, node, create=create)
+
         node.before_save(form, node, create=create)
         node.save()
         return node
 
+    def get_create_links(self, active=tuple()):
+        nav = []
+        if self.node:
+            for name, factory in getNodeFactories():
+                if self.can('create', factory):
+                    nav.append({
+                        'key': name,
+                        'url': self.node.permalink('create', name),
+                        'title': name,
+                        'children': [],
+                        'active': name in active,
+                    })
+        return nav
+
+    def get_convert_to_links(self, active=tuple()):
+        nav = []
+        for name, factory in getNodeFactories():
+            if self.can('create', factory):
+                nav.append({
+                    'key': name,
+                    'url': self.node.permalink('convert', name),
+                    'title': name,
+                    'children': [],
+                    'active': name in active,
+                })
+        return nav
+
+    def nav(self, active=tuple()):
+        nav = []
+
+        # Edit
+        if self.node and self.can('update'):
+            key = 'update'
+            link = self.node.permalink('update')
+            nav.append({
+                'key': key,
+                'url': link,
+                'title': _('Edit'),
+                'children': [],
+                'active': key in active,
+            })
+
+        # Create
+        create_links = self.get_create_links()
+        if create_links:
+            key = 'create'
+            nav.append({
+                'key': key,
+                'url': '#',
+                'title': _('New entry'),
+                'children': create_links,
+                'active': key in active,
+            })
+
+        return nav
+
 
 class ListView(NodeView):
     adapts(INode)
             'view': self,
             'node': self.node,
             'children': node_list,
-            'actions': self.list_actions(),
         }
         context.update(overrides or {})
         return render(self.request, template, context)
             'view': self,
             'node': self.node,
             'comments': comments,
-            'actions': self.details_actions(),
         }
         context.update(overrides)
 
             context['tag_form'] = TagForm(self.node)
 
         if 'comment_form' not in context:
-            context['comment_form'] = CommentForm()
+            context['comment_form'] = CommentForm(self.node)
 
         return render(self.request, template, context)
 
         self.node = node
         self.factory = factory
 
+    def nav(self, active=tuple()):
+        active = active or ('create',)
+        return super(CreateView, self).nav(active)
+
     def render(self):
         if not self.can('create', self.factory):
             return render(self.request, '403.html', status=403)
         if self.request.method == 'POST':
             form = self.get_form(self.request.POST)
             if form.is_valid():
-                child = self.form_save(form, create=True)
+                child = self.form_save(form)
                 if self.node:
                     return redirect(self.node.permalink())
                 else:
 
         return render(self.request, 'sboard/node_form.html', {
               'form': form,
-              'actions': self.list_actions(),
+              'view': self,
           })
 
 provideAdapter(CreateView, name="create")
 
 
 class UpdateView(NodeView):
+    def nav(self, active=tuple()):
+        active = active or ('update',)
+        return super(UpdateView, self).nav(active)
+
     def render(self):
         if not self.can('update'):
             return render(self.request, '403.html', status=403)
 
         if self.request.method == 'POST':
-            form = self.form(self.request.POST, instance=self.node)
+            form = self.get_form(self.request.POST)
             if form.is_valid():
-                node = self.form_save(form, create=False)
+                node = self.form_save(form, self.node)
                 return redirect(node.permalink())
         else:
-            form = self.form(instance=self.node,
-                             initial={'body': self.node.get_body()})
+            form = self.get_form()
 
         return render(self.request, 'sboard/node_form.html', {
               'form': form,
+              'view': self,
           })
 
 provideAdapter(UpdateView, name="update")
             doc = dict(self.node._doc)
             doc.pop('doc_type')
             node = self.model.wrap(doc)
-            form = self.form(self.request.POST, instance=node)
+            form = self.form(self.node, self.request.POST)
             if form.is_valid():
-                node = self.form_save(form, create=False)
+                node = self.form_save(form, node)
                 return redirect(node.permalink())
         else:
-            initial = dict(self.node._doc)
-            initial['body'] = self.node.get_body()
-            form = self.form(instance=self.node, initial=initial)
+            form = self.form(self.node)
 
         return render(self.request, 'sboard/node_form.html', {
               'form': form,

sboard/templates/sboard/node_details.html

   {% endif %}
 {% endblock %}
 
+
+{% block sidebar-items %}
+  <li class="nav-header">{% trans "Sprendimas" %}</li>
+  <li><a href="#">{% trans "Bendra informacija" %}</a></li>
+  <li class="active"><a href="#">{% trans "Testas" %}</a></li>
+{% endblock %}
+
+
 {% block content %}
-  <div class="row">
-    <ul class="nav nav-pills pull-right">
-      {% include "sboard/actions.html" %}
-    </ul>
-  </div>
+  <h1>{{ node.title }}</h1>
 
   {% block node_body %}
   {{ node.render_body }}

sboard/templates/sboard/node_form.html

-{% extends "base.html" %}
+{% extends "sboard/base.html" %}
 {% load markup %}
 {% load i18n %}
 

sboard/templates/sboard/node_list.html

   {% endif %}
 {% endblock %}
 
+
+{% block sidebar-items %}
+  <li class="nav-header">Sprendimai</li>
+  <li><a href="{% url node "testas" %}">{% trans "Testas" %}</a></li>
+{% endblock %}
+
+
 {% block content %}
-  <div class="row">
-    <ul class="nav nav-pills pull-right">
-      {% include "sboard/actions.html" %}
-    </ul>
-  </div>
-
   {% if children %}
     {% for child in children %}
     <div class="list-entry">

sboard/templates/sboard/profile.html

 {% load i18n %}
 {% load thumbnail %}
 
+{% block sidebar %}
+<ul class="nav nav-list">
+  {% include "sboard/actions.html" %}
+  <li class="nav-header">{% trans "Seimo narys" %}</li>
+  <li class="active"><a href="#">Bendra informacija</a></li>
+  <li><a href="#">Sprendimai</a></li>
+  <li><a href="#">Statistika</a></li>
+</ul>
+{% endblock %}
+
 {% block content %}
+<p><img src="{{ profile.avatar_url_big }}" style="float:left;margin-right:8px;" /></p>
 <h1>{{ profile.title }}</h1>
 {% if profile.dob %}
 <p>{% trans "Date of birth" %}: {{ profile.dob }} ({{ profile.age }})</p>
 {% if profile.home_page %}
 <p><a href="{{ profile.home_page }}">{% trans "Home page" %}</a></p>
 {% endif %}
-<p><img src="{{ profile.avatar_url_big }}" /></p>
 {% endblock %}
 import StringIO
 
-try:
-    from PIL import Image
-except ImportError:
-    import Image
+import Image
 
+from zope.component import ComponentLookupError
 from zope.component import getAdapter
 from zope.component import getMultiAdapter
 from zope.component import getUtility
 from django.http import HttpResponse
 
 from couchdbkit.client import ViewResults
-from couchdbkit.exceptions import MultipleResultsFound
-from couchdbkit.exceptions import NoResultFound
 
 from .factory import INodeFactory
 from .factory import get_search_handlers
 from .interfaces import INodeView
 from .models import couch
 from .models import getRootNode
+from .models import get_node_by_slug
 from .models import set_nodes_ambiguous
 
 
-def get_node(request, slug=None, action='', name=''):
-    key = None
-    if slug and '+' in slug:
-        slug, key = slug.split('+')
+def get_node_view(node, action='', name=''):
+    view = None
+    if name:
+        try:
+            factory = getUtility(INodeFactory, name)
+        except ComponentLookupError:
+            # /node/action/name/ - dynamic action, static name
+            view = getMultiAdapter((node, action), INodeView, name)
+        else:
+            # /node/action/factory/ - static action
+            view = getMultiAdapter((node, factory), INodeView, action)
+    else:
+        try:
+            # /node/action/ - static action
+            view = getAdapter(node, INodeView, action)
+        except ComponentLookupError:
+            # /node/action/ - dynamic action
+            view = getMultiAdapter((node, action), INodeView)
 
-    if key:
-        try:
-            return couch.get(key)
-        except NoResultFound:
-            return None
-
-    if slug is None or slug == '~':
-        return getRootNode()
-
-    query = couch.by_slug(key=slug, limit=20)
-    try:
-        return query.one(except_all=True)
-    except MultipleResultsFound:
-        return query
-    except NoResultFound:
-        return None
+    return view
 
 
 def node(request, slug=None, action='', name=''):
-    node = get_node(request, slug, action, name)
-
+    node = get_node_by_slug(slug)
     if node is None:
         raise Http404
     elif isinstance(node, ViewResults):
         return duplicate_slug_nodes(request, node)
 
-    if name:
-        # /node/factory/action
-        # /node/factory/str/
-        # /node/str/action/
-        # /node/str/str/
-        factory = getUtility(INodeFactory, name)
-        view = getMultiAdapter((node, factory), INodeView, action)
-        #view = getAdapter((node, factory), INodeView, action)
-        #view = getAdapter((node, factory, action), INodeView)
-        #view = getAdapter((node, name), INodeView, action)
-        #view = getAdapter((node, action, name), INodeView)
-    else:
-        # /node/action/
-        # /node/str/
-        view = getAdapter(node, INodeView, action)
-        #view = getAdapter((node, action), INodeView)
-
+    view = get_node_view(node, action, name)
     view.request = request
     return view.render()