Commit 0cb2ca2c by benjaoming

Merge pull request #188 from yedpodtrzitko/master

create root as a class-based view
parents 9528bf71 10a44575
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% block wiki_pagetitle %}{% trans "Create root article" %}{% endblock %} {% block wiki_pagetitle %}{% trans "Create root article" %}{% endblock %}
{% block wiki_contents %} {% block wiki_contents %}
{% addtoblock "js" %} {% addtoblock "js" %}
{% for js in editor.Media.js %} {% for js in editor.Media.js %}
<script type="text/javascript" src="{{ STATIC_URL }}{{ js }}"></script> <script type="text/javascript" src="{{ STATIC_URL }}{{ js }}"></script>
...@@ -23,17 +23,17 @@ ...@@ -23,17 +23,17 @@
<p class="lead"> <p class="lead">
{% trans "You have django-wiki installed... but there are no articles. So it's time to create the first one, the root article. In the beginning, it will only be editable by administrators, but you can define permissions after." %} {% trans "You have django-wiki installed... but there are no articles. So it's time to create the first one, the root article. In the beginning, it will only be editable by administrators, but you can define permissions after." %}
</p> </p>
<h2 class="page-header">{% trans "Root article" %}</h2> <h2 class="page-header">{% trans "Root article" %}</h2>
<form method="POST" class="form-horizontal"> <form method="POST" class="form-horizontal">
{% wiki_form create_form %} {% wiki_form form %}
<div class="form-group form-actions"> <div class="form-group form-actions">
<div class="col-lg-2"></div> <div class="col-lg-2"></div>
<div class="col-lg-10"> <div class="col-lg-10">
<input type="submit" name="save_changes" value="{% trans "Create root" %} &raquo;" class="btn btn-primary btn-large" /> <input type="submit" name="save_changes" value="{% trans "Create root" %} &raquo;" class="btn btn-primary btn-large" />
</div> </div>
</div> </div>
</form> </form>
{% endblock %} {% endblock %}
......
...@@ -6,10 +6,11 @@ from wiki.core.plugins import registry ...@@ -6,10 +6,11 @@ from wiki.core.plugins import registry
from wiki.views import article, accounts from wiki.views import article, accounts
from wiki.core.utils import get_class_from_str from wiki.core.utils import get_class_from_str
class WikiURLPatterns(object): class WikiURLPatterns(object):
''' '''
configurator for wiki urls. configurator for wiki urls.
To customize, you can define your own subclass, either overriding To customize, you can define your own subclass, either overriding
the view providers, or overriding the functions that collect the view providers, or overriding the functions that collect
views. views.
...@@ -30,7 +31,6 @@ class WikiURLPatterns(object): ...@@ -30,7 +31,6 @@ class WikiURLPatterns(object):
revision_change_view = 'wiki.views.article.change_revision' revision_change_view = 'wiki.views.article.change_revision'
revision_merge_view = 'wiki.views.article.merge' revision_merge_view = 'wiki.views.article.merge'
create_root = 'wiki.views.article.root_create'
search_view_class = settings.SEARCH_VIEW search_view_class = settings.SEARCH_VIEW
article_diff_view = 'wiki.views.article.diff' article_diff_view = 'wiki.views.article.diff'
...@@ -38,14 +38,14 @@ class WikiURLPatterns(object): ...@@ -38,14 +38,14 @@ class WikiURLPatterns(object):
signup_view_class = accounts.Signup signup_view_class = accounts.Signup
login_view_class = accounts.Login login_view_class = accounts.Login
logout_view_class = accounts.Logout logout_view_class = accounts.Logout
def get_urls(self): def get_urls(self):
urlpatterns = self.get_root_urls() urlpatterns = self.get_root_urls()
urlpatterns += self.get_accounts_urls() urlpatterns += self.get_accounts_urls()
urlpatterns += self.get_revision_urls() urlpatterns += self.get_revision_urls()
urlpatterns += self.get_article_urls() urlpatterns += self.get_article_urls()
urlpatterns += self.get_plugin_urls() urlpatterns += self.get_plugin_urls()
# This ALWAYS has to be the last of all the patterns since # This ALWAYS has to be the last of all the patterns since
# the paths in theory could wrongly match other targets. # the paths in theory could wrongly match other targets.
urlpatterns += self.get_article_path_urls() urlpatterns += self.get_article_path_urls()
...@@ -54,7 +54,7 @@ class WikiURLPatterns(object): ...@@ -54,7 +54,7 @@ class WikiURLPatterns(object):
def get_root_urls(self): def get_root_urls(self):
urlpatterns = patterns('', urlpatterns = patterns('',
url('^$', self.article_view_class.as_view(), name='root', kwargs={'path': ''}), url('^$', self.article_view_class.as_view(), name='root', kwargs={'path': ''}),
url('^create-root/$', self.create_root, name='root_create'), url('^create-root/$', article.CreateRootView.as_view(), name='root_create'),
url('^_search/$', get_class_from_str(self.search_view_class).as_view(), name='search'), url('^_search/$', get_class_from_str(self.search_view_class).as_view(), name='search'),
url('^_revision/diff/(?P<revision_id>\d+)/$', self.article_diff_view, name='diff'), url('^_revision/diff/(?P<revision_id>\d+)/$', self.article_diff_view, name='diff'),
) )
...@@ -70,7 +70,7 @@ class WikiURLPatterns(object): ...@@ -70,7 +70,7 @@ class WikiURLPatterns(object):
def get_revision_urls(self): def get_revision_urls(self):
urlpatterns = patterns('', urlpatterns = patterns('',
# This one doesn't work because it don't know where to redirect after... # 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+)/$', self.revision_change_view, name='change_revision'), url('^_revision/change/(?P<article_id>\d+)/(?P<revision_id>\d+)/$', self.revision_change_view, name='change_revision'),
url('^_revision/preview/(?P<article_id>\d+)/$', self.article_preview_view_class.as_view(), name='preview_revision'), url('^_revision/preview/(?P<article_id>\d+)/$', self.article_preview_view_class.as_view(), name='preview_revision'),
url('^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', self.revision_merge_view, name='merge_revision_preview', kwargs={'preview': True}), url('^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', self.revision_merge_view, name='merge_revision_preview', kwargs={'preview': True}),
......
...@@ -28,26 +28,26 @@ from django.http import Http404 ...@@ -28,26 +28,26 @@ from django.http import Http404
class ArticleView(ArticleMixin, TemplateView): class ArticleView(ArticleMixin, TemplateView):
template_name="wiki/view.html" template_name="wiki/view.html"
@method_decorator(get_article(can_read=True)) @method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return super(ArticleView, self).dispatch(request, article, *args, **kwargs) return super(ArticleView, self).dispatch(request, article, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['selected_tab'] = 'view' kwargs['selected_tab'] = 'view'
return ArticleMixin.get_context_data(self, **kwargs) return ArticleMixin.get_context_data(self, **kwargs)
class Create(FormView, ArticleMixin): class Create(FormView, ArticleMixin):
form_class = forms.CreateForm form_class = forms.CreateForm
template_name="wiki/create.html" template_name="wiki/create.html"
@method_decorator(get_article(can_write=True, can_create=True)) @method_decorator(get_article(can_write=True, can_create=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return super(Create, self).dispatch(request, article, *args, **kwargs) return super(Create, self).dispatch(request, article, *args, **kwargs)
def get_form(self, form_class): def get_form(self, form_class):
""" """
Returns an instance of the form to be used in this view. Returns an instance of the form to be used in this view.
...@@ -57,9 +57,9 @@ class Create(FormView, ArticleMixin): ...@@ -57,9 +57,9 @@ class Create(FormView, ArticleMixin):
initial['slug'] = self.request.GET.get('slug', None) initial['slug'] = self.request.GET.get('slug', None)
kwargs['initial'] = initial kwargs['initial'] = initial
form = form_class(self.request, self.urlpath, **kwargs) form = form_class(self.request, self.urlpath, **kwargs)
form.fields['slug'].widget = forms.TextInputPrepend(prepend='/'+self.urlpath.path) form.fields['slug'].widget = forms.TextInputPrepend(prepend='/'+self.urlpath.path)
return form return form
@transaction.commit_manually @transaction.commit_manually
def form_valid(self, form): def form_valid(self, form):
user=None user=None
...@@ -87,7 +87,7 @@ class Create(FormView, ArticleMixin): ...@@ -87,7 +87,7 @@ class Create(FormView, ArticleMixin):
'other_write': self.article.other_write, 'other_write': self.article.other_write,
}) })
messages.success(self.request, _(u"New article '%s' created.") % self.newpath.article.current_revision.title) messages.success(self.request, _(u"New article '%s' created.") % self.newpath.article.current_revision.title)
transaction.commit() transaction.commit()
# TODO: Handle individual exceptions better and give good feedback. # TODO: Handle individual exceptions better and give good feedback.
except Exception, e: except Exception, e:
...@@ -98,36 +98,36 @@ class Create(FormView, ArticleMixin): ...@@ -98,36 +98,36 @@ class Create(FormView, ArticleMixin):
messages.error(self.request, _(u"There was an error creating this article.")) messages.error(self.request, _(u"There was an error creating this article."))
transaction.commit() transaction.commit()
return redirect('wiki:get', '') return redirect('wiki:get', '')
url = self.get_success_url() url = self.get_success_url()
transaction.commit() transaction.commit()
return url return url
def get_success_url(self): def get_success_url(self):
return redirect('wiki:get', self.newpath.path) return redirect('wiki:get', self.newpath.path)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['parent_urlpath'] = self.urlpath kwargs['parent_urlpath'] = self.urlpath
kwargs['parent_article'] = self.article kwargs['parent_article'] = self.article
kwargs['create_form'] = kwargs.pop('form', None) kwargs['create_form'] = kwargs.pop('form', None)
kwargs['editor'] = editors.getEditor() kwargs['editor'] = editors.getEditor()
return super(Create, self).get_context_data(**kwargs) return super(Create, self).get_context_data(**kwargs)
class Delete(FormView, ArticleMixin): class Delete(FormView, ArticleMixin):
form_class = forms.DeleteForm form_class = forms.DeleteForm
template_name="wiki/delete.html" template_name="wiki/delete.html"
@method_decorator(get_article(can_write=True, not_locked=True, can_delete=True)) @method_decorator(get_article(can_write=True, not_locked=True, can_delete=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return self.dispatch1(request, article, *args, **kwargs) return self.dispatch1(request, article, *args, **kwargs)
def dispatch1(self, request, article, *args, **kwargs): def dispatch1(self, request, article, *args, **kwargs):
"""Deleted view needs to access this method without a decorator, """Deleted view needs to access this method without a decorator,
therefore it is separate.""" therefore it is separate."""
urlpath = kwargs.get('urlpath', None) urlpath = kwargs.get('urlpath', None)
# Where to go after deletion... # Where to go after deletion...
self.next = "" self.next = ""
self.cannot_delete_root = False self.cannot_delete_root = False
if urlpath and urlpath.parent: if urlpath and urlpath.parent:
...@@ -142,29 +142,29 @@ class Delete(FormView, ArticleMixin): ...@@ -142,29 +142,29 @@ class Delete(FormView, ArticleMixin):
self.next = reverse('wiki:get', kwargs={'article_id': art_obj.content_object.parent.article.id}) self.next = reverse('wiki:get', kwargs={'article_id': art_obj.content_object.parent.article.id})
else: else:
self.cannot_delete_root = True self.cannot_delete_root = True
return super(Delete, self).dispatch(request, article, *args, **kwargs) return super(Delete, self).dispatch(request, article, *args, **kwargs)
def get_initial(self): def get_initial(self):
return {'revision': self.article.current_revision} return {'revision': self.article.current_revision}
def get_form(self, form_class): def get_form(self, form_class):
form = super(Delete, self).get_form(form_class) form = super(Delete, self).get_form(form_class)
if self.article.can_moderate(self.request.user): if self.article.can_moderate(self.request.user):
form.fields['purge'].widget = forms.forms.CheckboxInput() form.fields['purge'].widget = forms.forms.CheckboxInput()
return form return form
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = FormView.get_form_kwargs(self) kwargs = FormView.get_form_kwargs(self)
kwargs['article'] = self.article kwargs['article'] = self.article
kwargs['has_children'] = bool(self.children_slice) kwargs['has_children'] = bool(self.children_slice)
return kwargs return kwargs
def form_valid(self, form): def form_valid(self, form):
cd = form.cleaned_data cd = form.cleaned_data
purge = cd['purge'] purge = cd['purge']
#If we are purging, only moderators can delete articles with children #If we are purging, only moderators can delete articles with children
cannot_delete_children = False cannot_delete_children = False
can_moderate = self.article.can_moderate(self.request.user) can_moderate = self.article.can_moderate(self.request.user)
...@@ -174,7 +174,7 @@ class Delete(FormView, ArticleMixin): ...@@ -174,7 +174,7 @@ class Delete(FormView, ArticleMixin):
if self.cannot_delete_root or cannot_delete_children: if self.cannot_delete_root or cannot_delete_children:
messages.error(self.request, _(u'This article cannot be deleted because it has children or is a root article.')) messages.error(self.request, _(u'This article cannot be deleted because it has children or is a root article.'))
return redirect('wiki:get', article_id=self.article.id) return redirect('wiki:get', article_id=self.article.id)
if can_moderate and purge: if can_moderate and purge:
# First, remove children # First, remove children
...@@ -190,15 +190,15 @@ class Delete(FormView, ArticleMixin): ...@@ -190,15 +190,15 @@ class Delete(FormView, ArticleMixin):
self.article.add_revision(revision) self.article.add_revision(revision)
messages.success(self.request, _(u'The article "%s" is now marked as deleted! Thanks for keeping the site free from unwanted material!') % revision.title) messages.success(self.request, _(u'The article "%s" is now marked as deleted! Thanks for keeping the site free from unwanted material!') % revision.title)
return self.get_success_url() return self.get_success_url()
def get_success_url(self): def get_success_url(self):
return redirect(self.next) return redirect(self.next)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
cannot_delete_children = False cannot_delete_children = False
if self.children_slice and not self.article.can_moderate(self.request.user): if self.children_slice and not self.article.can_moderate(self.request.user):
cannot_delete_children = True cannot_delete_children = True
kwargs['delete_form'] = kwargs.pop('form', None) kwargs['delete_form'] = kwargs.pop('form', None)
kwargs['cannot_delete_root'] = self.cannot_delete_root kwargs['cannot_delete_root'] = self.cannot_delete_root
kwargs['delete_children'] = self.children_slice[:20] kwargs['delete_children'] = self.children_slice[:20]
...@@ -209,19 +209,19 @@ class Delete(FormView, ArticleMixin): ...@@ -209,19 +209,19 @@ class Delete(FormView, ArticleMixin):
class Edit(FormView, ArticleMixin): class Edit(FormView, ArticleMixin):
"""Edit an article and process sidebar plugins.""" """Edit an article and process sidebar plugins."""
form_class = forms.EditForm form_class = forms.EditForm
template_name="wiki/edit.html" template_name="wiki/edit.html"
@method_decorator(get_article(can_write=True, not_locked=True)) @method_decorator(get_article(can_write=True, not_locked=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
self.sidebar_plugins = plugin_registry.get_sidebar() self.sidebar_plugins = plugin_registry.get_sidebar()
self.sidebar = [] self.sidebar = []
return super(Edit, self).dispatch(request, article, *args, **kwargs) return super(Edit, self).dispatch(request, article, *args, **kwargs)
def get_initial(self): def get_initial(self):
initial = FormView.get_initial(self) initial = FormView.get_initial(self)
for field_name in ['title', 'content']: for field_name in ['title', 'content']:
session_key = 'unsaved_article_%s_%d' % (field_name, self.article.id) session_key = 'unsaved_article_%s_%d' % (field_name, self.article.id)
if session_key in self.request.session.keys(): if session_key in self.request.session.keys():
...@@ -229,7 +229,7 @@ class Edit(FormView, ArticleMixin): ...@@ -229,7 +229,7 @@ class Edit(FormView, ArticleMixin):
initial[field_name] = content initial[field_name] = content
del self.request.session[session_key] del self.request.session[session_key]
return initial return initial
def get_form(self, form_class): def get_form(self, form_class):
""" """
Checks from querystring data that the edit form is actually being saved, Checks from querystring data that the edit form is actually being saved,
...@@ -241,7 +241,7 @@ class Edit(FormView, ArticleMixin): ...@@ -241,7 +241,7 @@ class Edit(FormView, ArticleMixin):
kwargs['files'] = None kwargs['files'] = None
kwargs['no_clean'] = True kwargs['no_clean'] = True
return form_class(self.request, self.article.current_revision, **kwargs) return form_class(self.request, self.article.current_revision, **kwargs)
def get_sidebar_form_classes(self): def get_sidebar_form_classes(self):
"""Returns dictionary of form classes for the sidebar. If no form class is """Returns dictionary of form classes for the sidebar. If no form class is
specified, puts None in dictionary. Keys in the dictionary are used specified, puts None in dictionary. Keys in the dictionary are used
...@@ -250,7 +250,7 @@ class Edit(FormView, ArticleMixin): ...@@ -250,7 +250,7 @@ class Edit(FormView, ArticleMixin):
for cnt, plugin in enumerate(self.sidebar_plugins): for cnt, plugin in enumerate(self.sidebar_plugins):
form_classes['form%d' % cnt] = (plugin, plugin.sidebar.get('form_class', None)) form_classes['form%d' % cnt] = (plugin, plugin.sidebar.get('form_class', None))
return form_classes return form_classes
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# Generate sidebar forms # Generate sidebar forms
self.sidebar_forms = [] self.sidebar_forms = []
...@@ -262,7 +262,7 @@ class Edit(FormView, ArticleMixin): ...@@ -262,7 +262,7 @@ class Edit(FormView, ArticleMixin):
form = None form = None
self.sidebar.append((plugin, form)) self.sidebar.append((plugin, form))
return super(Edit, self).get(request, *args, **kwargs) return super(Edit, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
# Generate sidebar forms # Generate sidebar forms
self.sidebar_forms = [] self.sidebar_forms = []
...@@ -277,19 +277,19 @@ class Edit(FormView, ArticleMixin): ...@@ -277,19 +277,19 @@ class Edit(FormView, ArticleMixin):
messages.success(self.request, usermessage) messages.success(self.request, usermessage)
else: else:
messages.success(self.request, _(u'Your changes were saved.')) messages.success(self.request, _(u'Your changes were saved.'))
title = form.cleaned_data['unsaved_article_title'] title = form.cleaned_data['unsaved_article_title']
content = form.cleaned_data['unsaved_article_content'] content = form.cleaned_data['unsaved_article_content']
if title != self.article.current_revision.title or content != self.article.current_revision.content: if title != self.article.current_revision.title or content != self.article.current_revision.content:
request.session['unsaved_article_title_%d' % self.article.id] = title request.session['unsaved_article_title_%d' % self.article.id] = title
request.session['unsaved_article_content_%d' % self.article.id] = content request.session['unsaved_article_content_%d' % self.article.id] = content
messages.warning(request, _('Please note that your article text has not yet been saved!')) messages.warning(request, _('Please note that your article text has not yet been saved!'))
if self.urlpath: if self.urlpath:
return redirect('wiki:edit', path=self.urlpath.path) return redirect('wiki:edit', path=self.urlpath.path)
return redirect('wiki:edit', article_id=self.article.id) return redirect('wiki:edit', article_id=self.article.id)
else: else:
form = Form(self.article, self.request) form = Form(self.article, self.request)
setattr(form, 'form_id', form_id) setattr(form, 'form_id', form_id)
...@@ -297,9 +297,9 @@ class Edit(FormView, ArticleMixin): ...@@ -297,9 +297,9 @@ class Edit(FormView, ArticleMixin):
form = None form = None
self.sidebar.append((plugin, form)) self.sidebar.append((plugin, form))
return super(Edit, self).post(request, *args, **kwargs) return super(Edit, self).post(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
"""Create a new article revision when the edit form is valid """Create a new article revision when the edit form is valid
(does not concern any sidebar forms!).""" (does not concern any sidebar forms!)."""
revision = models.ArticleRevision() revision = models.ArticleRevision()
revision.inherit_predecessor(self.article) revision.inherit_predecessor(self.article)
...@@ -311,13 +311,13 @@ class Edit(FormView, ArticleMixin): ...@@ -311,13 +311,13 @@ class Edit(FormView, ArticleMixin):
self.article.add_revision(revision) self.article.add_revision(revision)
messages.success(self.request, _(u'A new revision of the article was succesfully added.')) messages.success(self.request, _(u'A new revision of the article was succesfully added.'))
return self.get_success_url() return self.get_success_url()
def get_success_url(self): def get_success_url(self):
"""Go to the article view page when the article has been saved""" """Go to the article view page when the article has been saved"""
if self.urlpath: if self.urlpath:
return redirect("wiki:get", path=self.urlpath.path) return redirect("wiki:get", path=self.urlpath.path)
return redirect('wiki:get', article_id=self.article.id) return redirect('wiki:get', article_id=self.article.id)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['edit_form'] = kwargs.pop('form', None) kwargs['edit_form'] = kwargs.pop('form', None)
kwargs['editor'] = editors.getEditor() kwargs['editor'] = editors.getEditor()
...@@ -329,16 +329,16 @@ class Edit(FormView, ArticleMixin): ...@@ -329,16 +329,16 @@ class Edit(FormView, ArticleMixin):
class Deleted(Delete): class Deleted(Delete):
"""Tell a user that an article has been deleted. If user has permissions, """Tell a user that an article has been deleted. If user has permissions,
let user restore and possibly purge the deleted article and children.""" let user restore and possibly purge the deleted article and children."""
template_name="wiki/deleted.html" template_name="wiki/deleted.html"
form_class = forms.DeleteForm form_class = forms.DeleteForm
@method_decorator(get_article(can_read=True, deleted_contents=True)) @method_decorator(get_article(can_read=True, deleted_contents=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
self.urlpath = kwargs.get('urlpath', None) self.urlpath = kwargs.get('urlpath', None)
self.article = article self.article = article
if self.urlpath: if self.urlpath:
deleted_ancestor = self.urlpath.first_deleted_ancestor() deleted_ancestor = self.urlpath.first_deleted_ancestor()
if deleted_ancestor is None: if deleted_ancestor is None:
...@@ -347,16 +347,16 @@ class Deleted(Delete): ...@@ -347,16 +347,16 @@ class Deleted(Delete):
elif deleted_ancestor != self.urlpath: elif deleted_ancestor != self.urlpath:
# An ancestor was deleted, so redirect to that deleted page # An ancestor was deleted, so redirect to that deleted page
return redirect('wiki:deleted', path=deleted_ancestor.path) return redirect('wiki:deleted', path=deleted_ancestor.path)
else: else:
if not article.current_revision.deleted: if not article.current_revision.deleted:
return redirect('wiki:get', article_id=article.id) return redirect('wiki:get', article_id=article.id)
# Restore # Restore
if request.GET.get('restore', False): if request.GET.get('restore', False):
can_restore = not article.current_revision.locked and article.can_delete(request.user) can_restore = not article.current_revision.locked and article.can_delete(request.user)
can_restore = can_restore or article.can_moderate(request.user) can_restore = can_restore or article.can_moderate(request.user)
if can_restore: if can_restore:
revision = models.ArticleRevision() revision = models.ArticleRevision()
revision.inherit_predecessor(self.article) revision.inherit_predecessor(self.article)
...@@ -369,9 +369,9 @@ class Deleted(Delete): ...@@ -369,9 +369,9 @@ class Deleted(Delete):
return redirect('wiki:get', path=self.urlpath.path) return redirect('wiki:get', path=self.urlpath.path)
else: else:
return redirect('wiki:get', article_id=article.id) return redirect('wiki:get', article_id=article.id)
return super(Deleted, self).dispatch1(request, article, *args, **kwargs) return super(Deleted, self).dispatch1(request, article, *args, **kwargs)
def get_initial(self): def get_initial(self):
return {'revision': self.article.current_revision, return {'revision': self.article.current_revision,
'purge': True} 'purge': True}
...@@ -383,30 +383,30 @@ class Deleted(Delete): ...@@ -383,30 +383,30 @@ class Deleted(Delete):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['purge_form'] = kwargs.pop('form', None) kwargs['purge_form'] = kwargs.pop('form', None)
return super(Delete, self).get_context_data(**kwargs) return super(Delete, self).get_context_data(**kwargs)
class Source(ArticleMixin, TemplateView): class Source(ArticleMixin, TemplateView):
template_name="wiki/source.html" template_name="wiki/source.html"
@method_decorator(get_article(can_read=True)) @method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return super(Source, self).dispatch(request, article, *args, **kwargs) return super(Source, self).dispatch(request, article, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['selected_tab'] = 'source' kwargs['selected_tab'] = 'source'
return ArticleMixin.get_context_data(self, **kwargs) return ArticleMixin.get_context_data(self, **kwargs)
class History(ListView, ArticleMixin): class History(ListView, ArticleMixin):
template_name="wiki/history.html" template_name="wiki/history.html"
allow_empty = True allow_empty = True
context_object_name = 'revisions' context_object_name = 'revisions'
paginate_by = 10 paginate_by = 10
def get_queryset(self): def get_queryset(self):
return models.ArticleRevision.objects.filter(article=self.article).order_by('-created') return models.ArticleRevision.objects.filter(article=self.article).order_by('-created')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
# Is this a bit of a hack? Use better inheritance? # Is this a bit of a hack? Use better inheritance?
kwargs_article = ArticleMixin.get_context_data(self, **kwargs) kwargs_article = ArticleMixin.get_context_data(self, **kwargs)
...@@ -415,20 +415,20 @@ class History(ListView, ArticleMixin): ...@@ -415,20 +415,20 @@ class History(ListView, ArticleMixin):
kwargs.update(kwargs_listview) kwargs.update(kwargs_listview)
kwargs['selected_tab'] = 'history' kwargs['selected_tab'] = 'history'
return kwargs return kwargs
@method_decorator(get_article(can_read=True)) @method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return super(History, self).dispatch(request, article, *args, **kwargs) return super(History, self).dispatch(request, article, *args, **kwargs)
class Dir(ListView, ArticleMixin): class Dir(ListView, ArticleMixin):
template_name="wiki/dir.html" template_name="wiki/dir.html"
allow_empty = True allow_empty = True
context_object_name = 'directory' context_object_name = 'directory'
model = models.URLPath model = models.URLPath
paginate_by = 30 paginate_by = 30
@method_decorator(get_article(can_read=True)) @method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
self.filter_form = forms.DirFilterForm(request.GET) self.filter_form = forms.DirFilterForm(request.GET)
...@@ -447,7 +447,7 @@ class Dir(ListView, ArticleMixin): ...@@ -447,7 +447,7 @@ class Dir(ListView, ArticleMixin):
children = children.active() children = children.active()
children = children.select_related_common().order_by('article__current_revision__title') children = children.select_related_common().order_by('article__current_revision__title')
return children return children
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs_article = ArticleMixin.get_context_data(self, **kwargs) kwargs_article = ArticleMixin.get_context_data(self, **kwargs)
kwargs_listview = ListView.get_context_data(self, **kwargs) kwargs_listview = ListView.get_context_data(self, **kwargs)
...@@ -455,7 +455,7 @@ class Dir(ListView, ArticleMixin): ...@@ -455,7 +455,7 @@ class Dir(ListView, ArticleMixin):
kwargs.update(kwargs_listview) kwargs.update(kwargs_listview)
kwargs['filter_query'] = self.query kwargs['filter_query'] = self.query
kwargs['filter_form'] = self.filter_form kwargs['filter_form'] = self.filter_form
# Update each child's ancestor cache so the lookups don't have # Update each child's ancestor cache so the lookups don't have
# to be repeated. # to be repeated.
updated_children = kwargs[self.context_object_name] updated_children = kwargs[self.context_object_name]
...@@ -467,11 +467,11 @@ class Dir(ListView, ArticleMixin): ...@@ -467,11 +467,11 @@ class Dir(ListView, ArticleMixin):
class SearchView(ListView): class SearchView(ListView):
template_name="wiki/search.html" template_name="wiki/search.html"
paginate_by = 25 paginate_by = 25
context_object_name = "articles" context_object_name = "articles"
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
# Do not allow anonymous users to search if they cannot read content # Do not allow anonymous users to search if they cannot read content
if request.user.is_anonymous() and not settings.ANONYMOUS: if request.user.is_anonymous() and not settings.ANONYMOUS:
...@@ -482,7 +482,7 @@ class SearchView(ListView): ...@@ -482,7 +482,7 @@ class SearchView(ListView):
else: else:
self.query = None self.query = None
return super(SearchView, self).dispatch(request, *args, **kwargs) return super(SearchView, self).dispatch(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
if not self.query: if not self.query:
return models.Article.objects.get_empty_query_set() return models.Article.objects.get_empty_query_set()
...@@ -491,15 +491,15 @@ class SearchView(ListView): ...@@ -491,15 +491,15 @@ class SearchView(ListView):
if not permissions.can_moderate(models.URLPath.root().article, self.request.user): if not permissions.can_moderate(models.URLPath.root().article, self.request.user):
articles = articles.active().can_read(self.request.user) articles = articles.active().can_read(self.request.user)
return articles return articles
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs = ListView.get_context_data(self, **kwargs) kwargs = ListView.get_context_data(self, **kwargs)
kwargs['search_form'] = self.search_form kwargs['search_form'] = self.search_form
kwargs['search_query'] = self.query kwargs['search_query'] = self.query
return kwargs return kwargs
class Plugin(View): class Plugin(View):
def dispatch(self, request, path=None, slug=None, **kwargs): def dispatch(self, request, path=None, slug=None, **kwargs):
kwargs['path'] = path kwargs['path'] = path
for plugin in plugin_registry.get_plugins().values(): for plugin in plugin_registry.get_plugins().values():
...@@ -508,15 +508,15 @@ class Plugin(View): ...@@ -508,15 +508,15 @@ class Plugin(View):
raise Http404() raise Http404()
class Settings(ArticleMixin, TemplateView): class Settings(ArticleMixin, TemplateView):
permission_form_class = forms.PermissionsForm permission_form_class = forms.PermissionsForm
template_name="wiki/settings.html" template_name="wiki/settings.html"
@method_decorator(login_required) @method_decorator(login_required)
@method_decorator(get_article(can_read=True)) @method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
return super(Settings, self).dispatch(request, article, *args, **kwargs) return super(Settings, self).dispatch(request, article, *args, **kwargs)
def get_form_classes(self,): def get_form_classes(self,):
""" """
Return all settings forms that can be filled in Return all settings forms that can be filled in
...@@ -532,9 +532,9 @@ class Settings(ArticleMixin, TemplateView): ...@@ -532,9 +532,9 @@ class Settings(ArticleMixin, TemplateView):
# could be mixed up with a different instance # could be mixed up with a different instance
# Use strategy from Edit view... # Use strategy from Edit view...
setattr(settings_forms[i], 'action', 'form%d' % i) setattr(settings_forms[i], 'action', 'form%d' % i)
return settings_forms return settings_forms
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
self.forms = [] self.forms = []
for Form in self.get_form_classes(): for Form in self.get_form_classes():
...@@ -552,24 +552,24 @@ class Settings(ArticleMixin, TemplateView): ...@@ -552,24 +552,24 @@ class Settings(ArticleMixin, TemplateView):
form = Form(self.article, self.request) form = Form(self.article, self.request)
self.forms.append(form) self.forms.append(form)
return super(Settings, self).get(*args, **kwargs) return super(Settings, self).get(*args, **kwargs)
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
self.forms = [] self.forms = []
# There is a bug where articles fetched with select_related have bad boolean field https://code.djangoproject.com/ticket/15040 # There is a bug where articles fetched with select_related have bad boolean field https://code.djangoproject.com/ticket/15040
# We fetch a fresh new article for this reason # We fetch a fresh new article for this reason
new_article = models.Article.objects.get(id=self.article.id) new_article = models.Article.objects.get(id=self.article.id)
for Form in self.get_form_classes(): for Form in self.get_form_classes():
self.forms.append(Form(new_article, self.request)) self.forms.append(Form(new_article, self.request))
return super(Settings, self).get(*args, **kwargs) return super(Settings, self).get(*args, **kwargs)
def get_success_url(self): def get_success_url(self):
if self.urlpath: if self.urlpath:
return redirect('wiki:settings', path=self.urlpath.path) return redirect('wiki:settings', path=self.urlpath.path)
return redirect('wiki:settings', article_id=self.article.id) return redirect('wiki:settings', article_id=self.article.id)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['selected_tab'] = 'settings' kwargs['selected_tab'] = 'settings'
kwargs['forms'] = self.forms kwargs['forms'] = self.forms
...@@ -590,9 +590,9 @@ def change_revision(request, article, revision_id=None, urlpath=None): ...@@ -590,9 +590,9 @@ def change_revision(request, article, revision_id=None, urlpath=None):
return redirect('wiki:history', article_id=article.id) return redirect('wiki:history', article_id=article.id)
class Preview(ArticleMixin, TemplateView): class Preview(ArticleMixin, TemplateView):
template_name="wiki/preview_inline.html" template_name="wiki/preview_inline.html"
@method_decorator(get_article(can_read=True, deleted_contents=True)) @method_decorator(get_article(can_read=True, deleted_contents=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
revision_id = request.GET.get('r', None) revision_id = request.GET.get('r', None)
...@@ -604,7 +604,7 @@ class Preview(ArticleMixin, TemplateView): ...@@ -604,7 +604,7 @@ class Preview(ArticleMixin, TemplateView):
else: else:
self.revision = None self.revision = None
return super(Preview, self).dispatch(request, article, *args, **kwargs) return super(Preview, self).dispatch(request, article, *args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
edit_form = forms.EditForm(request, self.article.current_revision, request.POST, preview=True) edit_form = forms.EditForm(request, self.article.current_revision, request.POST, preview=True)
if edit_form.is_valid(): if edit_form.is_valid():
...@@ -612,87 +612,87 @@ class Preview(ArticleMixin, TemplateView): ...@@ -612,87 +612,87 @@ class Preview(ArticleMixin, TemplateView):
self.content = edit_form.cleaned_data['content'] self.content = edit_form.cleaned_data['content']
self.preview = True self.preview = True
return super(Preview, self).get(request, *args, **kwargs) return super(Preview, self).get(request, *args, **kwargs)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if self.revision and not self.title: if self.revision and not self.title:
self.title = self.revision.title self.title = self.revision.title
if self.revision and not self.content: if self.revision and not self.content:
self.content = self.revision.content self.content = self.revision.content
return super(Preview, self).get( request, *args, **kwargs) return super(Preview, self).get( request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs['title'] = self.title kwargs['title'] = self.title
kwargs['revision'] = self.revision kwargs['revision'] = self.revision
kwargs['content'] = self.content kwargs['content'] = self.content
kwargs['preview'] = self.preview kwargs['preview'] = self.preview
return ArticleMixin.get_context_data(self, **kwargs) return ArticleMixin.get_context_data(self, **kwargs)
@json_view @json_view
def diff(request, revision_id, other_revision_id=None): def diff(request, revision_id, other_revision_id=None):
revision = get_object_or_404(models.ArticleRevision, id=revision_id) revision = get_object_or_404(models.ArticleRevision, id=revision_id)
if not other_revision_id: if not other_revision_id:
other_revision = revision.previous_revision other_revision = revision.previous_revision
baseText = other_revision.content if other_revision else "" baseText = other_revision.content if other_revision else ""
newText = revision.content newText = revision.content
differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
diff = differ.compare(baseText.splitlines(1), newText.splitlines(1)) diff = differ.compare(baseText.splitlines(1), newText.splitlines(1))
other_changes = [] other_changes = []
if not other_revision or other_revision.title != revision.title: if not other_revision or other_revision.title != revision.title:
other_changes.append((_(u'New title'), revision.title)) other_changes.append((_(u'New title'), revision.title))
return dict(diff=list(diff), other_changes=other_changes) return dict(diff=list(diff), other_changes=other_changes)
# TODO: Throw in a class-based view # TODO: Throw in a class-based view
@get_article(can_write=True) @get_article(can_write=True)
def merge(request, article, revision_id, urlpath=None, template_file="wiki/preview_inline.html", preview=False): def merge(request, article, revision_id, urlpath=None, template_file="wiki/preview_inline.html", preview=False):
revision = get_object_or_404(models.ArticleRevision, article=article, id=revision_id) revision = get_object_or_404(models.ArticleRevision, article=article, id=revision_id)
current_text = article.current_revision.content if article.current_revision else "" current_text = article.current_revision.content if article.current_revision else ""
new_text = revision.content new_text = revision.content
content = simple_merge(current_text, new_text) content = simple_merge(current_text, new_text)
# Save new revision # Save new revision
if not preview: if not preview:
old_revision = article.current_revision old_revision = article.current_revision
if revision.deleted: if revision.deleted:
c = RequestContext(request, {'error_msg': _(u'You cannot merge with a deleted revision'), c = RequestContext(request, {'error_msg': _(u'You cannot merge with a deleted revision'),
'article': article, 'article': article,
'urlpath': urlpath}) 'urlpath': urlpath})
return render_to_response("wiki/error.html", context_instance=c) return render_to_response("wiki/error.html", context_instance=c)
new_revision = models.ArticleRevision() new_revision = models.ArticleRevision()
new_revision.inherit_predecessor(article) new_revision.inherit_predecessor(article)
new_revision.deleted = False new_revision.deleted = False
new_revision.locked = False new_revision.locked = False
new_revision.title=article.current_revision.title new_revision.title=article.current_revision.title
new_revision.content=content new_revision.content=content
new_revision.automatic_log = (_(u'Merge between revision #%(r1)d and revision #%(r2)d') % new_revision.automatic_log = (_(u'Merge between revision #%(r1)d and revision #%(r2)d') %
{'r1': revision.revision_number, {'r1': revision.revision_number,
'r2': old_revision.revision_number}) 'r2': old_revision.revision_number})
article.add_revision(new_revision, save=True) article.add_revision(new_revision, save=True)
old_revision.simpleplugin_set.all().update(article_revision=new_revision) old_revision.simpleplugin_set.all().update(article_revision=new_revision)
revision.simpleplugin_set.all().update(article_revision=new_revision) revision.simpleplugin_set.all().update(article_revision=new_revision)
messages.success(request, _(u'A new revision was created: Merge between revision #%(r1)d and revision #%(r2)d') % messages.success(request, _(u'A new revision was created: Merge between revision #%(r1)d and revision #%(r2)d') %
{'r1': revision.revision_number, {'r1': revision.revision_number,
'r2': old_revision.revision_number}) 'r2': old_revision.revision_number})
if urlpath: if urlpath:
return redirect('wiki:edit', path=urlpath.path) return redirect('wiki:edit', path=urlpath.path)
else: else:
return redirect('wiki:edit', article_id=article.id) return redirect('wiki:edit', article_id=article.id)
c = RequestContext(request, {'article': article, c = RequestContext(request, {'article': article,
'title': article.current_revision.title, 'title': article.current_revision.title,
'revision': None, 'revision': None,
...@@ -702,31 +702,37 @@ def merge(request, article, revision_id, urlpath=None, template_file="wiki/previ ...@@ -702,31 +702,37 @@ def merge(request, article, revision_id, urlpath=None, template_file="wiki/previ
'content': content}) 'content': content})
return render_to_response(template_file, context_instance=c) return render_to_response(template_file, context_instance=c)
# TODO: Should be a class-based view
def root_create(request): class CreateRootView(FormView):
try: form_class = forms.CreateRootForm
root = models.URLPath.root() template_name = 'wiki/create_root.html'
if not root.article:
def dispatch(self, request, *args, **kwargs):
if not request.user.is_superuser:
return redirect(settings.LOGIN_URL + "?next=" + reverse("wiki:root_create"))
try:
root = models.URLPath.root()
except NoRootURL:
pass
else:
if root.article:
return redirect('wiki:get', path=root.path)
# TODO: This is too dangerous... let's say there is no root.article and we end up here, # TODO: This is too dangerous... let's say there is no root.article and we end up here,
# then it might cascade to delete a lot of things on an existing installation.... / benjaoming # then it might cascade to delete a lot of things on an existing installation.... / benjaoming
root.delete() root.delete()
raise NoRootURL return super(CreateRootView, self).dispatch(request, *args, **kwargs)
return redirect('wiki:get', path=root.path)
except NoRootURL:
pass
if not request.user.is_superuser:
return redirect(settings.LOGIN_URL + "?next=" + reverse("wiki:root_create"))
if request.method == 'POST':
create_form = forms.CreateRootForm(request.POST)
if create_form.is_valid():
models.URLPath.create_root(title=create_form.cleaned_data["title"],
content=create_form.cleaned_data["content"],
request=request)
return redirect("wiki:root")
else:
create_form = forms.CreateRootForm()
c = RequestContext(request, {'create_form': create_form,
'editor': editors.getEditor(),})
return render_to_response("wiki/create_root.html", context_instance=c)
def form_valid(self, form):
models.URLPath.create_root(
title=form.cleaned_data["title"],
content=form.cleaned_data["content"],
request=self.request
)
return redirect("wiki:root")
def get_context_data(self, **kwargs):
data = super(CreateRootView, self).get_context_data(**kwargs)
data['editor'] = editors.getEditor()
return data
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