Commit 4ab97010 by Bridger Maxwell

Merge branch 'master' of git://github.com/benjaoming/django-wiki

parents c053503a b85791d5
...@@ -67,6 +67,14 @@ Please use these function calls rather than writing your own include() call - th ...@@ -67,6 +67,14 @@ Please use these function calls rather than writing your own include() call - th
The above line puts the wiki in */* so it's important to put it at the end of your urlconf. You can also put it in */wiki* by putting `'^wiki/'` as the pattern. The above line puts the wiki in */* so it's important to put it at the end of your urlconf. You can also put it in */wiki* by putting `'^wiki/'` as the pattern.
### Settings
For now, look in [wiki/conf/settings.py](wiki/conf/settings.py) to see a list of available settings.
### Other tips
1. **Account handling:** There are simple views that handle login, logout and signup. They are on by default. Make sure to set settings.LOGIN_URL to point to your login page as many wiki views may redirect to a login page.
Plugins Plugins
------------ ------------
......
...@@ -13,11 +13,11 @@ Not implemented - will be ASAP ...@@ -13,11 +13,11 @@ Not implemented - will be ASAP
* Key-value meta data * Key-value meta data
* Index views for urlpaths * Index views for urlpaths
* Searching * Searching
* South migrations **Soon** * South migrations **Done**
* View source for read-only articles + locked status * View source for read-only articles + locked status
* Global moderator permission **Almost done** (need to add grant form for users with *grant* permissions) * Global moderator permission **Almost done** (need to add grant form for users with *grant* permissions)
* Are you sure you wanna leave this page? * Are you sure you wanna leave this page?
* Special view for deleted articles w/ restore button * Special view for deleted articles w/ restore button **Done**
Ideas Ideas
===== =====
......
...@@ -9,6 +9,12 @@ ADMINS = ( ...@@ -9,6 +9,12 @@ ADMINS = (
# ('Your Name', 'your_email@example.com'), # ('Your Name', 'your_email@example.com'),
) )
from django.core.urlresolvers import reverse_lazy
LOGIN_REDIRECT_URL = reverse_lazy('wiki:get', kwargs={'path': ''})
LOGIN_URL = '/_accounts/login/'
LOGOUT_URL = '/_accounts/logout/'
MANAGERS = ADMINS MANAGERS = ADMINS
DATABASES = { DATABASES = {
......
...@@ -9,6 +9,8 @@ URL_CASE_SENSITIVE = getattr(django_settings, 'WIKI_URL_CASE_SENSITIVE', False) ...@@ -9,6 +9,8 @@ URL_CASE_SENSITIVE = getattr(django_settings, 'WIKI_URL_CASE_SENSITIVE', False)
APP_LABEL = 'wiki' APP_LABEL = 'wiki'
WIKI_LANGUAGE = 'markdown' WIKI_LANGUAGE = 'markdown'
# The editor class to use -- maybe a 3rd party or your own...? You can always
# extend the built-in editor and customize it....
EDITOR = getattr(django_settings, 'WIKI_EDITOR', 'wiki.editors.MarkItUp') EDITOR = getattr(django_settings, 'WIKI_EDITOR', 'wiki.editors.MarkItUp')
# This slug is used in URLPath if an article has been deleted. The children of the # This slug is used in URLPath if an article has been deleted. The children of the
...@@ -16,9 +18,11 @@ EDITOR = getattr(django_settings, 'WIKI_EDITOR', 'wiki.editors.MarkItUp') ...@@ -16,9 +18,11 @@ EDITOR = getattr(django_settings, 'WIKI_EDITOR', 'wiki.editors.MarkItUp')
# and all their content. # and all their content.
LOST_AND_FOUND_SLUG = getattr(django_settings, 'WIKI_LOST_AND_FOUND_SLUG', 'lost-and-found') LOST_AND_FOUND_SLUG = getattr(django_settings, 'WIKI_LOST_AND_FOUND_SLUG', 'lost-and-found')
# Do we want to log IPs?
LOG_IPS_ANONYMOUS = getattr(django_settings, 'WIKI_LOG_IPS_ANONYMOUS', True) LOG_IPS_ANONYMOUS = getattr(django_settings, 'WIKI_LOG_IPS_ANONYMOUS', True)
LOG_IPS_USERS = getattr(django_settings, 'WIKI_LOG_IPS_USERS', False) LOG_IPS_USERS = getattr(django_settings, 'WIKI_LOG_IPS_USERS', False)
# Sign up, login and logout views should be accessible
ACCOUNT_HANDLING = getattr(django_settings, 'WIKI_ACCOUNT_HANDLING', True) ACCOUNT_HANDLING = getattr(django_settings, 'WIKI_ACCOUNT_HANDLING', True)
if ACCOUNT_HANDLING: if ACCOUNT_HANDLING:
......
...@@ -5,6 +5,7 @@ _cache = {} ...@@ -5,6 +5,7 @@ _cache = {}
_settings_forms = [] _settings_forms = []
_markdown_extensions = [] _markdown_extensions = []
_article_tabs = [] _article_tabs = []
_sidebar = []
def register(PluginClass): def register(PluginClass):
""" """
...@@ -25,9 +26,13 @@ def register(PluginClass): ...@@ -25,9 +26,13 @@ def register(PluginClass):
settings_form = getattr(form_module, klassname) settings_form = getattr(form_module, klassname)
_settings_forms.append(settings_form) _settings_forms.append(settings_form)
if PluginClass.article_tab:
if getattr(PluginClass, 'article_tab', None):
_article_tabs.append(plugin) _article_tabs.append(plugin)
if getattr(PluginClass, 'sidebar', None):
_sidebar.append(plugin)
_markdown_extensions.extend(getattr(PluginClass, 'markdown_extensions', [])) _markdown_extensions.extend(getattr(PluginClass, 'markdown_extensions', []))
def get_plugins(): def get_plugins():
...@@ -37,4 +42,9 @@ def get_markdown_extensions(): ...@@ -37,4 +42,9 @@ def get_markdown_extensions():
return _markdown_extensions return _markdown_extensions
def get_article_tabs(): def get_article_tabs():
"""Returns plugin classes that should connect to the article tab menu"""
return _article_tabs return _article_tabs
def get_sidebar():
"""Returns plugin classes that should connect to the sidebar"""
return _sidebar
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf import settings as django_settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.http import HttpResponse, HttpResponseNotFound from django.http import HttpResponse, HttpResponseNotFound
...@@ -42,10 +43,7 @@ def get_article(func=None, can_read=True, can_write=False, deleted_contents=Fals ...@@ -42,10 +43,7 @@ def get_article(func=None, can_read=True, can_write=False, deleted_contents=Fals
path = kwargs.pop('path', None) path = kwargs.pop('path', None)
article_id = kwargs.pop('article_id', None) article_id = kwargs.pop('article_id', None)
if can_read: articles = models.Article.objects
articles = models.Article.objects.can_read(request.user)
if can_write:
articles = models.Article.objects.can_write(request.user)
# TODO: Is this the way to do it? # TODO: Is this the way to do it?
articles = articles.select_related() articles = articles.select_related()
...@@ -71,15 +69,28 @@ def get_article(func=None, can_read=True, can_write=False, deleted_contents=Fals ...@@ -71,15 +69,28 @@ def get_article(func=None, can_read=True, can_write=False, deleted_contents=Fals
except models.URLPath.DoesNotExist: except models.URLPath.DoesNotExist:
# TODO: Make a nice page # TODO: Make a nice page
return HttpResponseNotFound("This article was not found, and neither was the parent. This page should look nicer.") return HttpResponseNotFound("This article was not found, and neither was the parent. This page should look nicer.")
# TODO: If the article is not found but it exists, there is a permission error!
if urlpath.article: if urlpath.article:
article = get_object_or_404(articles, id=urlpath.article.id) article = get_object_or_404(articles, id=urlpath.article.id)
else: else:
# Somehow article is gone # Be robust: Somehow article is gone but urlpath exists... clean up
return_url = reverse('wiki:get', kwargs={'path': urlpath.parent.path}) return_url = reverse('wiki:get', kwargs={'path': urlpath.parent.path})
urlpath.delete() urlpath.delete()
return redirect(return_url) return redirect(return_url)
if can_read and not article.can_read(request.user):
if request.user.is_anonymous:
return redirect(django_settings.LOGIN_URL)
else:
pass
# TODO: Return a permission denied page
if can_write and not article.can_write(request.user):
if request.user.is_anonymous:
return redirect(django_settings.LOGIN_URL)
else:
pass
# TODO: Return a permission denied page
# If the article has been deleted, show a special page. # If the article has been deleted, show a special page.
if not deleted_contents and article.current_revision and article.current_revision.deleted: if not deleted_contents and article.current_revision and article.current_revision.deleted:
if urlpath: if urlpath:
......
...@@ -35,6 +35,7 @@ class EditForm(forms.Form): ...@@ -35,6 +35,7 @@ class EditForm(forms.Form):
def __init__(self, current_revision, *args, **kwargs): def __init__(self, current_revision, *args, **kwargs):
self.no_clean = kwargs.pop('no_clean', False)
self.preview = kwargs.pop('preview', False) self.preview = kwargs.pop('preview', False)
self.initial_revision = current_revision self.initial_revision = current_revision
self.presumed_revision = None self.presumed_revision = None
...@@ -68,6 +69,8 @@ class EditForm(forms.Form): ...@@ -68,6 +69,8 @@ class EditForm(forms.Form):
def clean(self): def clean(self):
cd = self.cleaned_data cd = self.cleaned_data
if self.no_clean:
return cd
if not str(self.initial_revision.id) == str(self.presumed_revision): if not str(self.initial_revision.id) == str(self.presumed_revision):
raise forms.ValidationError(_(u'While you were editing, someone else changed the revision. Your contents have been automatically merged with the new contents. Please review the text below.')) raise forms.ValidationError(_(u'While you were editing, someone else changed the revision. Your contents have been automatically merged with the new contents. Please review the text below.'))
if cd['title'] == self.initial_revision.title and cd['content'] == self.initial_revision.content: if cd['title'] == self.initial_revision.title and cd['content'] == self.initial_revision.content:
......
...@@ -44,7 +44,7 @@ class Article(models.Model): ...@@ -44,7 +44,7 @@ class Article(models.Model):
if user == self.owner: if user == self.owner:
return True return True
if self.group_read: if self.group_read:
if group == self.group: if self.group and group == self.group:
return True return True
if self.group and user and user.groups.filter(group=group): if self.group and user and user.groups.filter(group=group):
return True return True
...@@ -58,7 +58,7 @@ class Article(models.Model): ...@@ -58,7 +58,7 @@ class Article(models.Model):
if user == self.owner: if user == self.owner:
return True return True
if self.group_write: if self.group_write:
if group == self.group: if self.group and group == self.group:
return True return True
if self.group and user and user.groups.filter(group=group): if self.group and user and user.groups.filter(group=group):
return True return True
......
...@@ -32,6 +32,8 @@ class ArticlePlugin(models.Model): ...@@ -32,6 +32,8 @@ class ArticlePlugin(models.Model):
deleted = models.BooleanField(default=False) deleted = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
def purge(self): def purge(self):
"""Remove related contents completely, ie. media files.""" """Remove related contents completely, ie. media files."""
pass pass
...@@ -106,7 +108,7 @@ class RevisionPlugin(ArticlePlugin): ...@@ -106,7 +108,7 @@ class RevisionPlugin(ArticlePlugin):
super(RevisionPlugin, self).__init__(*args, **kwargs) super(RevisionPlugin, self).__init__(*args, **kwargs)
if not self.id and not 'article' in kwargs: if not self.id and not 'article' in kwargs:
raise RevisionPluginCreateError("Keyword argument 'article' expected.") raise RevisionPluginCreateError("Keyword argument 'article' expected.")
self.article = kwargs['article'] self.article = kwargs['article']
def get_logmessage(self): def get_logmessage(self):
return _(u"A plugin was changed") return _(u"A plugin was changed")
...@@ -121,6 +123,7 @@ class RevisionPlugin(ArticlePlugin): ...@@ -121,6 +123,7 @@ class RevisionPlugin(ArticlePlugin):
new_revision.save() new_revision.save()
self.revision = new_revision self.revision = new_revision
super(RevisionPlugin, self).save(*args, **kwargs)
class Meta: class Meta:
app_label = settings.APP_LABEL app_label = settings.APP_LABEL
......
...@@ -24,12 +24,9 @@ class BasePlugin(object): ...@@ -24,12 +24,9 @@ class BasePlugin(object):
class PluginSidebarFormMixin(object): class PluginSidebarFormMixin(object):
def __init__(self, plugin_instance, *args, **kwargs): def get_usermessage(self):
pass
kwargs['prefix'] = plugin_instance.slug
class PluginSettingsFormMixin(object): class PluginSettingsFormMixin(object):
settings_form_headline = _(u'Notifications') settings_form_headline = _(u'Notifications')
......
...@@ -2,6 +2,9 @@ from django.conf import settings as django_settings ...@@ -2,6 +2,9 @@ from django.conf import settings as django_settings
SLUG = "attachments" SLUG = "attachments"
# Allow anonymous users to upload (not nice on an open network)
ANONYMOUS = getattr(django_settings, 'WIKI_ATTACHMENTS_ANONYMOUS', False)
# Maximum file sizes: Please using something like LimitRequestBody on # Maximum file sizes: Please using something like LimitRequestBody on
# your web server. # your web server.
# http://httpd.apache.org/docs/2.2/mod/core.html#LimitRequestBody # http://httpd.apache.org/docs/2.2/mod/core.html#LimitRequestBody
......
...@@ -82,12 +82,16 @@ ...@@ -82,12 +82,16 @@
<div id="collapse_upload" class="accordion-body collapse{% if form.errors %} in{% endif %}"> <div id="collapse_upload" class="accordion-body collapse{% if form.errors %} in{% endif %}">
<div class="accordion-inner"> <div class="accordion-inner">
{% if anonymous_disallowed %}
{% include "wiki/includes/anonymous_blocked.html" %}
{% else %}
<form method="POST" class="form-vertical" id="attachment_form" enctype="multipart/form-data"> <form method="POST" class="form-vertical" id="attachment_form" enctype="multipart/form-data">
{% wiki_form form %} {% wiki_form form %}
<button type="submit" name="save" value="1" class="btn btn-large"> <button type="submit" name="save" value="1" class="btn btn-large">
{% trans "Upload file" %} {% trans "Upload file" %}
</button> </button>
</form> </form>
{% endif %}
</div> </div>
</div> </div>
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf import settings as django_settings
from django.contrib import messages
from django.db import transaction
from django.db.models import Q
from django.http import Http404
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.generic.edit import FormView
from django.db.models import Q
from wiki.views.mixins import ArticleMixin
from wiki.decorators import get_article
from wiki.plugins.attachments import forms
from wiki.plugins.attachments import models
from django.contrib import messages
from django.views.generic.base import TemplateView, View from django.views.generic.base import TemplateView, View
from wiki.core.http import send_file from django.views.generic.edit import FormView
from django.http import Http404
from django.db import transaction
from django.views.generic.list import ListView from django.views.generic.list import ListView
from wiki.core.http import send_file
from wiki.decorators import get_article
from wiki.plugins.attachments import models, settings, forms
from wiki.views.mixins import ArticleMixin
class AttachmentView(ArticleMixin, FormView): class AttachmentView(ArticleMixin, FormView):
form_class = forms.AttachmentForm form_class = forms.AttachmentForm
...@@ -34,6 +35,9 @@ class AttachmentView(ArticleMixin, FormView): ...@@ -34,6 +35,9 @@ class AttachmentView(ArticleMixin, FormView):
# WARNING! The below decorator silences other exceptions that may occur! # WARNING! The below decorator silences other exceptions that may occur!
#@transaction.commit_manually #@transaction.commit_manually
def form_valid(self, form): def form_valid(self, form):
if self.request.user.is_anonymous and not settings.ANONYMOUS:
return redirect(django_settings.LOGIN_URL)
try: try:
attachment_revision = form.save(commit=False) attachment_revision = form.save(commit=False)
attachment = models.Attachment() attachment = models.Attachment()
...@@ -59,6 +63,7 @@ class AttachmentView(ArticleMixin, FormView): ...@@ -59,6 +63,7 @@ class AttachmentView(ArticleMixin, FormView):
kwargs['attachments'] = self.attachments kwargs['attachments'] = self.attachments
kwargs['search_form'] = forms.SearchForm() kwargs['search_form'] = forms.SearchForm()
kwargs['selected_tab'] = 'attachments' kwargs['selected_tab'] = 'attachments'
kwargs['anonymous_disallowed'] = self.request.user.is_anonymous and not settings.ANONYMOUS
return super(AttachmentView, self).get_context_data(**kwargs) return super(AttachmentView, self).get_context_data(**kwargs)
......
...@@ -26,6 +26,7 @@ class AttachmentPlugin(plugins.BasePlugin): ...@@ -26,6 +26,7 @@ class AttachmentPlugin(plugins.BasePlugin):
url('^download/(?P<attachment_id>\d+)/revision/(?P<revision_id>\d+)/$', views.AttachmentDownloadView.as_view(), name='attachments_download'), url('^download/(?P<attachment_id>\d+)/revision/(?P<revision_id>\d+)/$', views.AttachmentDownloadView.as_view(), name='attachments_download'),
url('^change/(?P<attachment_id>\d+)/revision/(?P<revision_id>\d+)/$', views.AttachmentChangeRevisionView.as_view(), name='attachments_revision_change'), url('^change/(?P<attachment_id>\d+)/revision/(?P<revision_id>\d+)/$', views.AttachmentChangeRevisionView.as_view(), name='attachments_revision_change'),
) )
article_tab = (_(u'Attachments'), "icon-file") article_tab = (_(u'Attachments'), "icon-file")
article_view = views.AttachmentView().dispatch article_view = views.AttachmentView().dispatch
......
from django import forms
from django.utils.translation import ugettext as _
from wiki.plugins import PluginSidebarFormMixin
from wiki.plugins.images import models
class SidebarForm(forms.ModelForm, PluginSidebarFormMixin):
def __init__(self, *args, **kwargs):
self.article = kwargs.pop('article')
super(SidebarForm, self).__init__(*args, **kwargs)
def get_usermessage(self):
return _(u"New image %s was successfully uploaded. You can use it by selecting it from the list of available images.") % self.instance.get_filename()
class Meta:
model = models.Image
fields = ('image',)
\ No newline at end of file
...@@ -9,13 +9,14 @@ class Image(RevisionPlugin): ...@@ -9,13 +9,14 @@ class Image(RevisionPlugin):
image = models.ImageField(upload_to=settings.IMAGE_PATH) image = models.ImageField(upload_to=settings.IMAGE_PATH)
caption = models.CharField(max_length=2056, null=True, blank=True) def get_filename(self):
if self.image:
def render_caption(self): return self.image.path.split('/')[-1]
"""Returns a rendered version of the caption. Should only use a
subset of the rendering machine."""
pass
class Meta: class Meta:
verbose_name = _(u'image') verbose_name = _(u'image')
verbose_name_plural = _(u'images') verbose_name_plural = _(u'images')
def __unicode__(self):
return _(u'Image: %s') % self.get_filename()
\ No newline at end of file
from django.conf import settings as django_settings from django.conf import settings as django_settings
# Where to store images # Where to store images
IMAGE_PATH = getattr(django_settings, "WIKI_IMAGE_PATH", 'wiki/images/%aid/') IMAGE_PATH = getattr(django_settings, 'WIKI_IMAGE_PATH', "wiki/images/%aid/")
# Allow anonymous users to upload (not nice on an open network)
ANONYMOUS = getattr(django_settings, 'WIKI_ATTACHMENTS_ANONYMOUS', False)
SLUG = 'images'
\ No newline at end of file
{% load i18n wiki_tags wiki_images_tags humanize %}
<h4>{% trans "Available images" %}</h4>
<p>{% trans "Click on an image below to insert in your text. The format of the code inserted is:" %}<br /><code>[image:id alignment caption text]</code></p>
<table class="table table-bordered table-striped">
<tr>
<th>{% trans "File" %}</th>
<th>{% trans "Added" %}</th>
</tr>
{% for image in article|images_for_article %}
<tr>
<td>{{ image.get_filename }}</td>
<td>{{ image.created|naturaltime }}</td>
</tr>
{% endfor %}
</table>
<hr />
<h4>{% trans "Add new image" %}</h4>
{% if form.non_field_errors %}
{% if form_error_title %}<h4 class="alert-heading">{{ form_error_title }}</h4>{% endif %}
{% for error_message in form.non_field_errors %}
<div class="alert alert-block alert-error">
{{ error_message }}
</div>
{% endfor %}
{% endif %}
{% for field in form %}
<p id="div_{{ field.auto_id }}" class="fields {% if field.errors %} error{% endif %}">
{% if field.label %}
<!--<label for="{{ field.id_for_label }}" class="{% if field.field.required %}requiredField{% endif %}">
{{ field.label|safe }}
</label>-->
{% endif %}
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<div id="error_{{ forloop.counter }}_{{ field.auto_id }}" class="help-block"><strong>{{ error }}</strong></div>
{% endfor %}
{% endif %}
</p>
{% if field.help_text %}
<p id="hint_{{ field.auto_id }}" class="help-block">{{ field.help_text|safe }}</p>
{% endif %}
{% endfor %}
<p>
<button type="submit" name="{{ plugin.slug }}_save" value="1" class="btn btn-large">
<span class="icon-upload"></span>
{% trans "Add image" %}
</button>
</p>
from django import template
from wiki.plugins.images import models
register = template.Library()
@register.filter
def images_for_article(article):
return models.Image.objects.filter(revision__article=article)
from wiki.views.mixins import ArticleMixin
from django.views.generic.base import TemplateView
from django.utils.decorators import method_decorator
from wiki.decorators import get_article
class ImageView(ArticleMixin, TemplateView):
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
return super(ImageView, self).dispatch(request, article, *args, **kwargs)
\ No newline at end of file
# -*- coding: utf-8 -*-
from django.conf.urls.defaults import patterns, url
from django.utils.translation import ugettext as _
from wiki.core import plugins_registry
from wiki import plugins
from wiki.plugins.images import views, models, settings, forms
from wiki.plugins.notifications import ARTICLE_EDIT
class ImagePlugin(plugins.BasePlugin):
#settings_form = 'wiki.plugins.notifications.forms.SubscriptionForm'
slug = settings.SLUG
urlpatterns = patterns('',
url('^$', views.ImageView.as_view(), name='images_index'),
)
sidebar = {'headline': _('Images'),
'icon_class': 'icon-picture',
'template': 'wiki/plugins/images/sidebar.html',
'form_class': forms.SidebarForm,
'get_form_kwargs': (lambda a: {'instance': models.Image(article=a)})}
# List of notifications to construct signal handlers for. This
# is handled inside the notifications plugin.
notifications = [{'model': models.Image,
'message': lambda obj: _(u"An image was added: %s") % obj.get_filename(),
'key': ARTICLE_EDIT,
'created': True,
'get_article': lambda obj: obj.revision.article}
]
#markdown_extensions = [AttachmentExtension()]
def __init__(self):
#print "I WAS LOADED!"
pass
plugins_registry.register(ImagePlugin)
...@@ -7,11 +7,9 @@ ...@@ -7,11 +7,9 @@
.markItUp {padding: 0; width: auto;} .markItUp {padding: 0; width: auto;}
textarea.markItUp {font-size: 16px; padding: 10px; float: none; display: block; width: 100%; } textarea.markItUp {font-size: 16px; padding: 10px; float: none; display: block; width: 100%; height: 400px; font-size: 13px; color: #222; }
.markItUpHeader {float: none; display: block; } .markItUpContainer {margin-right: 20px; width: -20px;}
.markItUpContainer {margin-right: 40px;;}
.markItUp .markItUpButton1 a { .markItUp .markItUpButton1 a {
background-image:url(images/h1.png); background-image:url(images/h1.png);
......
...@@ -12,8 +12,12 @@ ...@@ -12,8 +12,12 @@
<!-- TODO: Put all this stuff in Less --> <!-- TODO: Put all this stuff in Less -->
<style> <style>
#id_title {font-size: 20px; height: 25px; padding: 10px; width: 400px;} #div_id_title .asteriskField{display:none}
#id_summary {width: 95%} #id_title {font-size: 20px; height: 30px; padding: 6px; width: 98%;}
#id_summary {width: 98%; padding: 6px;}
#article_edit_form label {max-width: 120px;}
#article_edit_form .controls {margin-left: 140px;}
.form-horizontal label { font-size: 18px; font-weight: bold; color: #777;} .form-horizontal label { font-size: 18px; font-weight: bold; color: #777;}
#settings_form label {font-size: inherit; font-weight: normal;} #settings_form label {font-size: inherit; font-weight: normal;}
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% block wiki_contents_tab %} {% block wiki_contents_tab %}
<form method="POST" class="form-horizontal"> <form method="POST" class="form-horizontal" id="article_edit_form" enctype="multipart/form-data">
{% include "wiki/includes/editor.html" %} {% include "wiki/includes/editor.html" %}
<div class="form-actions"> <div class="form-actions">
<button type="submit" name="preview" value="1" class="btn btn-large" onclick="$('#previewModal').modal('show'); this.form.target='previewWindow'; this.form.action='{% url 'wiki:preview' path=urlpath.path article_id=article.id %}'"> <button type="submit" name="preview" value="1" class="btn btn-large" onclick="$('#previewModal').modal('show'); this.form.target='previewWindow'; this.form.action='{% url 'wiki:preview' path=urlpath.path article_id=article.id %}'">
......
{% load i18n %}
{% load url from future %}
<em>
{% url 'wiki:signup' as signup_url %}
{% url 'wiki:login' as login_url %}
{% if login_url and signup_url %}
{% blocktrans %}
You need to <a href="{{ login_url }}">log in</a> or <a href="{{ signup_url }}">sign up</a> to use this function.
{% endblocktrans %}
{% else %}
{% trans "You need to log in og sign up to use this function." %}
{% endif %}
</em>
...@@ -2,6 +2,15 @@ ...@@ -2,6 +2,15 @@
{% with selected_tab as selected %} {% with selected_tab as selected %}
<li class="pull-right{% if selected == "settings" %} active{% endif %}">
{% if not user.is_anonymous %}
<a href="{% url 'wiki:settings' article_id=article.id path=urlpath.path %}">
<span class="icon-wrench"></span>
{% trans "Settings" %}
</a>
{% endif %}
</li>
{% for plugin in article_tabs %} {% for plugin in article_tabs %}
<li class="pull-right{% if selected == plugin.slug %} active{% endif %}"> <li class="pull-right{% if selected == plugin.slug %} active{% endif %}">
<a href="{% url 'wiki:plugin' slug=plugin.slug article_id=article.id path=urlpath.path %}"> <a href="{% url 'wiki:plugin' slug=plugin.slug article_id=article.id path=urlpath.path %}">
...@@ -11,14 +20,6 @@ ...@@ -11,14 +20,6 @@
</li> </li>
{% endfor %} {% endfor %}
<li class="pull-right{% if selected == "settings" %} active{% endif %}">
{% if not user.is_anonymous %}
<a href="{% url 'wiki:settings' article_id=article.id path=urlpath.path %}">
<span class="icon-wrench"></span>
{% trans "Settings" %}
</a>
{% endif %}
</li>
<li class="pull-right{% if selected == "history" %} active{% endif %}"> <li class="pull-right{% if selected == "history" %} active{% endif %}">
<a href="{% url 'wiki:history' article_id=article.id path=urlpath.path %}"> <a href="{% url 'wiki:history' article_id=article.id path=urlpath.path %}">
<span class="icon-time"></span> <span class="icon-time"></span>
......
{% load wiki_tags %} {% load wiki_tags i18n %}
{% include "wiki/includes/editormedia.html" %} {% include "wiki/includes/editormedia.html" %}
<div style="width: 67%; min-width: 600px; float: left;">
{% wiki_form edit_form %} {% wiki_form edit_form %}
<script language="javascript">
$(document).ready(function() {
$("#id_revision").val('{{ article.current_revision.id }}');
});
</script>
</div>
<div style="width: 33%; min-width: 300px; float: right;">
<div style="padding-left: 40px;">
{% for plugin in sidebar %}
<div class="accordion" id="accordion_{{ plugin.slug }}">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" href="#collapse_{{ plugin.slug }}" data-toggle="collapse">
<h2>{{ plugin.sidebar.headline }} <span class="{{ plugin.sidebar.icon_class }}"></span></h2>
</a>
</div>
<div id="collapse_{{ plugin.slug }}" class="accordion-body collapse{% if form_images.errors %} in{% endif %}">
<div class="accordion-inner form-vertical">
{% if plugin.sidebar.template %}
{% with form_images as form and plugin as plugin %}
{% include plugin.sidebar.template %}
{% endwith %}
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div style="clear: both"></div>
...@@ -2,17 +2,19 @@ ...@@ -2,17 +2,19 @@
"""This is nothing but the usual handling of django user accounts, so """This is nothing but the usual handling of django user accounts, so
go ahead and replace it or disable it!""" go ahead and replace it or disable it!"""
from django.contrib.auth.models import User from django.conf import settings as django_settings
from django.contrib import messages
from django.contrib.auth import logout as auth_logout, login as auth_login from django.contrib.auth import logout as auth_logout, login as auth_login
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib import messages from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.generic.base import View from django.views.generic.base import View
from django.views.generic.edit import CreateView, FormView from django.views.generic.edit import CreateView, FormView
from wiki.models import URLPath from wiki.models import URLPath
from django.core.urlresolvers import reverse
class Signup(CreateView): class Signup(CreateView):
model = User model = User
...@@ -28,7 +30,6 @@ class Logout(View): ...@@ -28,7 +30,6 @@ class Logout(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
auth_logout(request) auth_logout(request)
messages.info(request, _(u"You are no longer logged in. Bye bye!")) messages.info(request, _(u"You are no longer logged in. Bye bye!"))
print redirect("wiki:get", URLPath.root().path)
return redirect("wiki:get", URLPath.root().path) return redirect("wiki:get", URLPath.root().path)
class Login(FormView): class Login(FormView):
...@@ -47,5 +48,5 @@ class Login(FormView): ...@@ -47,5 +48,5 @@ class Login(FormView):
messages.info(self.request, _(u"You are now logged in! Have fun!")) messages.info(self.request, _(u"You are now logged in! Have fun!"))
if self.request.GET.get("next", None): if self.request.GET.get("next", None):
return redirect(self.request.GET['next']) return redirect(self.request.GET['next'])
return redirect("wiki:get", URLPath.root().path) return redirect(django_settings.LOGIN_REDIRECT_URL)
...@@ -222,13 +222,53 @@ class Edit(FormView, ArticleMixin): ...@@ -222,13 +222,53 @@ class Edit(FormView, ArticleMixin):
@method_decorator(get_article(can_write=True)) @method_decorator(get_article(can_write=True))
def dispatch(self, request, article, *args, **kwargs): def dispatch(self, request, article, *args, **kwargs):
self.sidebar_plugins = plugins_registry.get_sidebar()
self.sidebar_forms = {}
for plugin in self.sidebar_plugins:
sidebar_form_class = plugin.sidebar.get('form_class', None)
if sidebar_form_class:
form_kwargs = {}
form_kwargs['prefix'] = plugin.slug
form_kwargs['article'] = article
form_kwargs.update(plugin.sidebar['get_form_kwargs'](article))
plugin.sidebar_form_context = 'form_' + plugin.slug
if request.POST.get(plugin.slug+'_save', '') == '1':
form_kwargs['data'] = request.POST
form_kwargs['files'] = request.FILES
self.sidebar_forms[plugin.sidebar_form_context] = sidebar_form_class(**form_kwargs)
return super(Edit, self).dispatch(request, article, *args, **kwargs) return super(Edit, 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.
""" """
return form_class(self.article.current_revision, **self.get_form_kwargs()) kwargs = self.get_form_kwargs()
if self.request.POST.get('save', '') != '1':
kwargs['no_clean'] = True
return form_class(self.article.current_revision, **kwargs)
def post(self, request, *args, **kwargs):
# Check if any of the plugin form data is supposed to be saved
for plugin in self.sidebar_plugins:
if self.request.POST.get(plugin.slug+'_save', '') == '1':
form = self.sidebar_forms[plugin.sidebar_form_context]
if form.is_valid():
form.save()
message = form.get_usermessage()
if message:
messages.success(request, message)
#if self.urlpath:
# return redirect('wiki:edit', path=self.urlpath.path)
#else:
# return redirect('wiki:edit', article_id=self.article.id)
if self.request.POST.get('save', '') == '1':
return super(Edit, self).post(request, *args, **kwargs)
else:
return super(Edit, self).get(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
revision = models.ArticleRevision() revision = models.ArticleRevision()
...@@ -252,6 +292,10 @@ class Edit(FormView, ArticleMixin): ...@@ -252,6 +292,10 @@ class Edit(FormView, ArticleMixin):
kwargs['edit_form'] = kwargs.pop('form', None) kwargs['edit_form'] = kwargs.pop('form', None)
kwargs['editor'] = editors.editor kwargs['editor'] = editors.editor
kwargs['selected_tab'] = 'edit' kwargs['selected_tab'] = 'edit'
kwargs['sidebar'] = self.sidebar_plugins
kwargs.update(self.sidebar_forms)
return super(Edit, self).get_context_data(**kwargs) return super(Edit, self).get_context_data(**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