Commit 8408f01f by benjaoming

More class-based views. Mixin class for Article-related views handling…

More class-based views. Mixin class for Article-related views handling permissions etc. More complex plugin structure for easy creation of plugins with very easy integration in the article tab menu etc.
parent fa4af858
Not implemented - will be ASAP
==============================
* Permission system in settings tab
* Notification system
* Permission system in settings tab **Done**
* Notification system **Almost done**
* Simple user account handling: login/register etc.
* Implement notifications, revision log messages and user messages thoroughly
* Attachment plugin **In the making**
* Image plugin
* Example plugin
Ideas
=====
......@@ -19,5 +23,6 @@ Management script
=================
* Cleanup deleted Image's image files
* Cleanup revisions
* Cleanup attachments
* Cleanup revisions + plugin revisions
......@@ -24,4 +24,4 @@ def register(PluginClass):
form_module = import_module(modulename)
settings_form = getattr(form_module, klassname)
_settings_forms.append(settings_form)
\ No newline at end of file
......@@ -2,7 +2,6 @@ from django.utils import simplejson as json
from django.http import HttpResponse, HttpResponseForbidden,\
HttpResponseNotFound
import models
from wiki.core.exceptions import NoRootURL
from django.shortcuts import redirect, get_object_or_404
from django.core.urlresolvers import reverse
......@@ -21,10 +20,11 @@ def get_article(func=None, can_read=True, can_write=False):
calling the decorated func with this ID."""
def the_func(request, *args, **kwargs):
import models
path = kwargs.pop('path', None)
article_id = kwargs.pop('article_id', None)
urlpath = None
if not path is None:
try:
......
......@@ -3,7 +3,7 @@ from django import forms
from django.utils.translation import ugettext as _
from itertools import chain
import editors
from editors import editor
from django.utils.safestring import mark_safe
from wiki import models
from django.forms.util import flatatt
......@@ -16,14 +16,14 @@ class CreateRoot(forms.Form):
title = forms.CharField(label=_(u'Title'), help_text=_(u'Initial title of the article. May be overridden with revision titles.'))
content = forms.CharField(label=_(u'Type in some contents'),
help_text=_(u'This is just the initial contents of your article. After creating it, you can use more complex features like adding plugins, meta data, related articles etc...'),
required=False, widget=editors.editor.get_widget())
required=False, widget=editor.get_widget())
class EditForm(forms.Form):
title = forms.CharField(label=_(u'Title'),)
content = forms.CharField(label=_(u'Contents'),
required=False, widget=editors.editor.get_widget())
required=False, widget=editor.get_widget())
summary = forms.CharField(label=_(u'Summary'), help_text=_(u'Give a short reason for your edit, which will be stated in the revision log.'),
required=False)
......@@ -178,7 +178,7 @@ class CreateForm(forms.Form):
title = forms.CharField(label=_(u'Title'),)
slug = forms.SlugField(label=_(u'Slug'), help_text=_(u"This will be the address where your article can be found. Use only alphanumeric characters and '-' or '_'."),)
content = forms.CharField(label=_(u'Contents'),
required=False, widget=editors.editor.get_widget())
required=False, widget=editor.get_widget())
summary = forms.CharField(label=_(u'Summary'), help_text=_(u"Write a brief message for the article's history log."),
required=False)
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{% trans "Settings" %}: {% article_for_object urlpath as article %}{{ article.current_revision.title }}{% endblock %}
{% block wiki_breadcrumbs %}
{% include "wiki/includes/breadcrumbs.html" %}
{% endblock %}
{% block wiki_contents %}
{% article_for_object urlpath as article %}
{% if article %}
<div class="tabbable tabs-top" style="margin-top: 40px;">
<ul class="nav nav-tabs">
{% with "attachments" as selected %}
{% include "wiki/includes/article_menu.html" %}
{% endwith %}
<li>
<h1 style="margin-top: -10px;">
{{ article.current_revision.title }}
</h1>
</li>
</ul>
<div class="tab-content">
Upload form coming up! List of attachments coming here and in the article text + a special markdown tag for including a link to each attachment in the article text.
</div>
</div>
<div class="tabbable tabs-below" style="margin-top: 20px;">
<ul class="nav nav-tabs">
<li style="margin-top: 10px;"><em>{% trans "Article last modified:" %} {{ article.current_revision.modified }}</em></li>
</ul>
</div>
{% else %}
{% trans "An article for this path does not exist." %}
{% endif %}
{% endblock %}
from django.utils.translation import ugettext as _
from django.views.generic.base import TemplateView
from django.utils.decorators import method_decorator
from wiki.core import plugins_registry
from wiki.views.mixins import ArticleMixin
from wiki.decorators import get_article
class AttachmentView(ArticleMixin, TemplateView):
template_name="wiki/plugins/attachments/tab.html"
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
return super(AttachmentView, self).dispatch(request, article, *args, **kwargs)
class AttachmentPlugin(plugins_registry.BasePlugin):
#settings_form = 'wiki.plugins.notifications.forms.SubscriptionForm'
slug = 'attachments'
article_tab = (_(u'Attachments'), "icon-file")
article_view = AttachmentView().dispatch
article_template_append = 'wiki/plugins/attachments/append.html'
def __init__(self):
#print "I WAS LOADED!"
pass
plugins_registry.register(AttachmentPlugin)
......@@ -19,14 +19,14 @@ class ArticleSubscription(wiki_models.pluginbase.ArticlePlugin, Subscription):
'type': self.notification_type.label})
def post_article_save(instance, **kwargs):
if kwargs.get('created', False):
if kwargs.get('created', True):
urlpath = wiki_models.URLPath.objects.filter(articles=instance)
if urlpath:
url = reverse('wiki:get_url', urlpath.path)
else:
url = None
notify(_(u'New article created: %s') % instance.title, settings.ARTICLE_CREATE,
target_object=instance.id, url=url)
target_object=instance, url=url)
def post_article_revision_save(instance, **kwargs):
if kwargs.get('created', False):
......
{% load i18n wiki_tags %}{% load url from future %}
{% for plugin in plugins %}
{% if plugin.article_tab %}
<li class="pull-right{% if selected == plugin.slug %} active{% endif %}">
<a href="{% url 'wiki:plugin_url' urlpath.path plugin.slug %}">
<span class="{{ plugin.article_tab.1 }}"></span>
{{ plugin.article_tab.0 }}
</a>
</li>
{% endif %}
{% endfor %}
<li class="pull-right{% if selected == "settings" %} active{% endif %}">
{% if not user.is_anonymous %}
<a href="{% url 'wiki:settings_url' urlpath.path %}">
......
# -*- coding: utf-8 -*-
from django.conf.urls.defaults import patterns, url
import views
from wiki.views import article
urlpatterns = patterns('',
url('^$', 'wiki.views.root', name='root', kwargs={'path': ''}),
url('^create-root/$', 'wiki.views.root_create', name='root_create'),
url('^_revision/diff/(\d+)/$', 'wiki.views.diff', name='diff'),
url('^$', article.ArticleView.as_view(), name='root', kwargs={'path': ''}),
url('^create-root/$', 'wiki.views.article.root_create', name='root_create'),
url('^_revision/diff/(\d+)/$', 'wiki.views.article.diff', name='diff'),
# This one doesn't work because it don't know where to redirect after...
url('^_revision/change/(?P<article_id>\d+)/(?P<revision_id>\d+)/$', 'wiki.views.change_revision', name='change_revision'),
url('^_revision/change/(?P<article_id>\d+)/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
url('^_revision/preview/(?P<article_id>\d+)/$', 'wiki.views.preview', name='preview_revision'),
url('^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', 'wiki.views.merge', name='merge_revision_preview', kwargs={'preview': True}),
url('^(?P<path>.+/|)_create/$', views.Create.as_view(), name='create_url'),
url('^(?P<path>.+/|)_edit/$', views.Edit.as_view(), name='edit_url'),
url('^(?P<path>.+/|)_preview/$', 'wiki.views.preview', name='preview_url'),
url('^(?P<path>.+/|)_history/$', views.History.as_view(), name='history_url'),
url('^(?P<path>.+/|)_settings/$', views.Settings.as_view(), name='settings_url'),
url('^(?P<path>.+/|)_revision/change/(?P<revision_id>\d+)/$', 'wiki.views.change_revision', name='change_revision_url'),
url('^(?P<path>.+/|)_revision/merge/(?P<revision_id>\d+)/$', 'wiki.views.merge', name='merge_revision_url'),
url('^(?P<path>.+/|)$', 'wiki.views.get_url', name='get_url'),
url('^_revision/preview/(?P<article_id>\d+)/$', 'wiki.views.article.preview', name='preview_revision'),
url('^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', 'wiki.views.article.merge', name='merge_revision_preview', kwargs={'preview': True}),
url('^(?P<path>.+/|)_create/$', article.Create.as_view(), name='create_url'),
url('^(?P<path>.+/|)_edit/$', article.Edit.as_view(), name='edit_url'),
url('^(?P<path>.+/|)_preview/$', 'wiki.views.article.preview', name='preview_url'),
url('^(?P<path>.+/|)_history/$', article.History.as_view(), name='history_url'),
url('^(?P<path>.+/|)_settings/$', article.Settings.as_view(), name='settings_url'),
url('^(?P<path>.+/|)_revision/change/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision_url'),
url('^(?P<path>.+/|)_revision/merge/(?P<revision_id>\d+)/$', 'wiki.views.article.merge', name='merge_revision_url'),
url('^(?P<path>.+/|)_plugin/(?P<slug>\w+)/$', article.Plugin.as_view(), name='plugin_url'),
url('^(?P<path>.+/|)$', article.ArticleView.as_view(), name='get_url'),
)
def get_pattern(app_name="wiki", namespace="wiki"):
......
......@@ -8,6 +8,9 @@ from wiki import models
from wiki import forms
from wiki import editors
from wiki.conf import settings
from wiki.core import plugins_registry
from mixins import ArticleMixin
from django.contrib import messages
from django.views.generic.list import ListView
......@@ -17,9 +20,8 @@ from django.utils.decorators import method_decorator
from django.views.generic.edit import FormView
from wiki.decorators import get_article
from django.views.generic.base import TemplateView
from django.views.generic.base import TemplateView, View
from wiki.core import plugins_registry
from wiki.core.diff import simple_merge
@get_article(can_read=True)
......@@ -49,23 +51,14 @@ def preview(request, article, urlpath=None, template_file="wiki/preview_inline.h
'content': content})
return render_to_response(template_file, c)
@get_article(can_read=True)
def root(request, article, template_file="wiki/article.html", urlpath=None):
c = RequestContext(request, {'urlpath': urlpath,
'article': article,})
return render_to_response(template_file, c)
class Edit(FormView):
class Edit(FormView, ArticleMixin):
form_class = forms.EditForm
template_name="wiki/edit.html"
@method_decorator(get_article(can_write=True))
def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.pop('urlpath', None)
self.article = article
return super(Edit, self).dispatch(request, *args, **kwargs)
return super(Edit, self).dispatch(request, article, *args, **kwargs)
def get_form(self, form_class):
"""
......@@ -98,23 +91,19 @@ class Edit(FormView):
return
def get_context_data(self, **kwargs):
kwargs['urlpath'] = self.urlpath
kwargs['article'] = self.article
kwargs['edit_form'] = kwargs.pop('form', None)
kwargs['editor'] = editors.editor
return super(Edit, self).get_context_data(**kwargs)
class Create(FormView):
class Create(FormView, ArticleMixin):
form_class = forms.CreateForm
template_name="wiki/create.html"
@method_decorator(get_article(can_write=True))
def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.pop('urlpath', None)
self.article = article
return super(Create, self).dispatch(request, *args, **kwargs)
return super(Create, self).dispatch(request, article, *args, **kwargs)
def get_form(self, form_class):
"""
......@@ -155,16 +144,22 @@ class Create(FormView):
kwargs['editor'] = editors.editor
return super(Create, self).get_context_data(**kwargs)
class Settings(TemplateView):
class Plugin(View):
def dispatch(self, request, path=None, slug=None, **kwargs):
kwargs['path'] = path
for plugin in plugins_registry._cache.values():
if getattr(plugin, 'slug', None) == slug:
return plugin.article_view(request, **kwargs)
class Settings(ArticleMixin, TemplateView):
permission_form_class = forms.PermissionsForm
template_name="wiki/settings.html"
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.pop('urlpath', None)
self.article = article
return super(Settings, self).dispatch(request, *args, **kwargs)
return super(Settings, self).dispatch(request, article, *args, **kwargs)
def get_form_classes(self,):
"""
......@@ -205,12 +200,10 @@ class Settings(TemplateView):
return redirect('wiki:settings_url', self.urlpath.path)
def get_context_data(self, **kwargs):
kwargs['urlpath'] = self.urlpath
kwargs['article'] = self.article
kwargs['forms'] = self.forms
return kwargs
return super(Settings, self).get_context_data(**kwargs)
class History(ListView):
class History(ListView, ArticleMixin):
template_name="wiki/history.html"
allow_empty = True
......@@ -221,15 +214,16 @@ class History(ListView):
return models.ArticleRevision.objects.filter(article=self.article).order_by('-created')
def get_context_data(self, **kwargs):
kwargs['urlpath'] = self.urlpath
kwargs['article'] = self.article
return super(History, self).get_context_data(**kwargs)
# Is this a bit of a hack? Use better inheritance?
kwargs_article = ArticleMixin.get_context_data(self, **kwargs)
kwargs_listview = ListView.get_context_data(self, **kwargs)
kwargs.update(kwargs_article)
kwargs.update(kwargs_listview)
return kwargs
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.pop('urlpath', None)
self.article = article
return super(History, self).dispatch(request, *args, **kwargs)
return super(History, self).dispatch(request, article, *args, **kwargs)
@get_article(can_write=True)
def change_revision(request, article, revision_id=None, urlpath=None):
......@@ -258,13 +252,14 @@ def root_create(request):
'editor': editors.editor,})
return render_to_response("wiki/article/create_root.html", c)
@get_article(can_read=True)
def get_url(request, article, template_file="wiki/article.html", urlpath=None):
c = RequestContext(request, {'urlpath': urlpath,
'article': article,})
return render_to_response(template_file, c)
class ArticleView(ArticleMixin, TemplateView, ):
template_name="wiki/article.html"
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
return super(ArticleView, self).dispatch(request, article, *args, **kwargs)
@json_view
def diff(request, revision_id, other_revision_id=None):
......
from django.views.generic.base import TemplateResponseMixin
from wiki.core import plugins_registry
class ArticleMixin(TemplateResponseMixin):
def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.pop('urlpath', None)
self.article = article
return super(ArticleMixin, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs['urlpath'] = self.urlpath
kwargs['article'] = self.article
kwargs['plugins'] = plugins_registry._cache.values()
return kwargs
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment