Commit f3dce909 by Christina Roberts Committed by GitHub

Merge pull request #24 from edx/christina/1_11_upgrade

Updates for Django 1.11.
parents 144a8162 f749c67a
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
from django.utils.translation import ugettext as _
import models
_disable_notifications = False
def notify(message, key, target_object=None, url=None):
"""
Notify subscribing users of a new event. Key can be any kind of string,
just make sure to reuse it where applicable! Object_id is some identifier
of an object, for instance if a user subscribes to a specific comment thread,
you could write:
notify("there was a response to your comment", "comment_response",
target_object=PostersObject,
url=reverse('comments:view', args=(PostersObject.id,)))
The below example notifies everyone subscribing to the "new_comments" key
with the message "New comment posted".
notify("New comment posted", "new_comments")
"""
if _disable_notifications:
return 0
if target_object:
if not isinstance(target_object, Model):
raise TypeError(_(u"You supplied a target_object that's not an instance of a django Model."))
object_id = target_object.id
else:
object_id = None
objects = models.Notification.create_notifications(key, object_id=object_id,
message=message, url=url)
return len(objects)
\ No newline at end of file
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models import Q
from django.db.models import Q, Model
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
......@@ -8,6 +8,8 @@ from django.contrib.contenttypes.models import ContentType
from django_notify import settings
_disable_notifications = False
class NotificationType(models.Model):
"""
Notification types are added on-the-fly by the
......@@ -105,3 +107,36 @@ class Notification(models.Model):
db_table = settings.DB_TABLE_PREFIX + '_notification'
verbose_name = _(u'notification')
verbose_name_plural = _(u'notifications')
def notify(message, key, target_object=None, url=None):
"""
Notify subscribing users of a new event. Key can be any kind of string,
just make sure to reuse it where applicable! Object_id is some identifier
of an object, for instance if a user subscribes to a specific comment thread,
you could write:
notify("there was a response to your comment", "comment_response",
target_object=PostersObject,
url=reverse('comments:view', args=(PostersObject.id,)))
The below example notifies everyone subscribing to the "new_comments" key
with the message "New comment posted".
notify("New comment posted", "new_comments")
"""
if _disable_notifications:
return 0
if target_object:
if not isinstance(target_object, Model):
raise TypeError(_(u"You supplied a target_object that's not an instance of a django Model."))
object_id = target_object.id
else:
object_id = None
objects = Notification.create_notifications(key, object_id=object_id,
message=message, url=url)
return len(objects)
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from django_notify import views
urlpatterns = patterns('',
url('^json/get/$', 'django_notify.views.get_notifications', name='json_get', kwargs={}),
url('^json/mark-read/$', 'django_notify.views.mark_read', name='json_mark_read_base', kwargs={}),
url('^json/mark-read/(\d+)/$', 'django_notify.views.mark_read', name='json_mark_read', kwargs={}),
url('^goto/(?P<notification_id>\d+)/$', 'django_notify.views.goto', name='goto', kwargs={}),
url('^goto/$', 'django_notify.views.goto', name='goto_base', kwargs={}),
)
urlpatterns = [
url('^json/get/$', views.get_notifications, name='json_get', kwargs={}),
url('^json/mark-read/$', views.mark_read, name='json_mark_read_base', kwargs={}),
url('^json/mark-read/(\d+)/$', views.mark_read, name='json_mark_read', kwargs={}),
url('^goto/(?P<notification_id>\d+)/$', views.goto, name='goto', kwargs={}),
url('^goto/$', views.goto, name='goto_base', kwargs={}),
]
def get_pattern(app_name="notify", namespace="notify"):
"""Every url resolution takes place as "notify:view_name".
......
django<1.9
South==1.0.1
Markdown<2.3.0
django-sekizai<0.7
django-mptt<0.8
sorl-thumbnail<13
\ No newline at end of file
django>=1.8,<2.0
Markdown>=2.6,<2.7
django-sekizai>=0.10
django-mptt>=0.8.6,<0.9
sorl-thumbnail>=12,<13
six>=1.10.0,<2.0.0
......@@ -29,7 +29,7 @@ package_data = dict(
setup(
name = "django-wiki",
version = "0.0.10",
version="0.0.11",
author = "Benjamin Bach",
author_email = "benjamin@overtag.dk",
description = ("A wiki system written for the Django framework."),
......@@ -39,7 +39,7 @@ setup(
long_description=read('README.md'),
zip_safe = False,
install_requires=[
'Django>=1.4',
'Django>=1.8',
'markdown',
'django-sekizai',
'django-mptt',
......
......@@ -3,7 +3,6 @@ from os import path as os_path
PROJECT_PATH = os_path.abspath(os_path.split(__file__)[0])
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@example.com'),
......@@ -47,22 +46,9 @@ MEDIA_URL = '/media/'
STATIC_ROOT = os_path.join(PROJECT_PATH, 'static')
STATIC_URL = '/static/'
STATICFILES_DIRS = (
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
SECRET_KEY = 'b^fv_)t39h%9p40)fnkfblo##jkr!$0)lkp6bpy!fi*f$4*92!'
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
......@@ -79,22 +65,31 @@ ROOT_URLCONF = 'testproject.urls'
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'testproject.wsgi.application'
TEMPLATE_DIRS = (
'templates',
)
TEMPLATE_CONTEXT_PROCESSORS =(
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'sekizai.context_processors.sekizai',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os_path.join(PROJECT_PATH, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
"django.contrib.auth.context_processors.auth",
"django.template.context_processors.debug",
"django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.request",
"django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
"sekizai.context_processors.sekizai",
],
'debug': DEBUG,
},
},
]
INSTALLED_APPS = (
INSTALLED_APPS = [
'django.contrib.humanize',
'django.contrib.auth',
'django.contrib.contenttypes',
......@@ -114,7 +109,7 @@ INSTALLED_APPS = (
'wiki.plugins.attachments',
'wiki.plugins.notifications',
'mptt',
)
]
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
......@@ -146,3 +141,6 @@ LOGGING = {
}
WIKI_ANONYMOUS_WRITE = True
# We disable this in edx-platform lms/envs/common.py, so disabling for test project also.
WIKI_USE_BOOTSTRAP_SELECT_WIDGET = False
from django.conf.urls import patterns, include, url
from django.conf.urls import include, url
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.static import serve as static_serve
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^notify/', include('django_notify.urls', namespace='notify')),
)
]
if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns()
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
urlpatterns += [
url(r'^media/(?P<path>.*)$', static_serve, {'document_root': settings.MEDIA_ROOT}),
]
from wiki.urls import get_pattern as get_wiki_pattern
from django_notify.urls import get_pattern as get_notify_pattern
urlpatterns += patterns('',
(r'^notify/', get_notify_pattern()),
(r'', get_wiki_pattern())
)
\ No newline at end of file
urlpatterns += [
url(r'^notify/', get_notify_pattern()),
url(r'', get_wiki_pattern()),
]
......@@ -6,7 +6,6 @@ from django.core.urlresolvers import reverse_lazy
URL_CASE_SENSITIVE = getattr(django_settings, 'WIKI_URL_CASE_SENSITIVE', False)
# Non-configurable (at the moment)
APP_LABEL = 'wiki'
WIKI_LANGUAGE = 'markdown'
# The editor class to use -- maybe a 3rd party or your own...? You can always
......
# Django 1.11 Widget.build_attrs has a different signature, designed for the new
# template based rendering. The previous version was more useful for our needs,
# so we restore that version.
# When support for Django < 1.11 is dropped, we should look at using the
# new template based rendering, at which point this probably won't be needed at all.
class BuildAttrsCompat(object):
def build_attrs_compat(self, extra_attrs=None, **kwargs):
"Helper function for building an attribute dictionary."
attrs = self.attrs.copy()
if extra_attrs is not None:
attrs.update(extra_attrs)
if kwargs is not None:
attrs.update(kwargs)
return attrs
......@@ -24,9 +24,9 @@ def response_forbidden(request, article, urlpath):
if request.user.is_anonymous():
return redirect(django_settings.LOGIN_URL)
else:
c = RequestContext(request, {'article': article,
'urlpath' : urlpath})
return HttpResponseForbidden(render_to_string("wiki/permission_denied.html", context_instance=c))
return HttpResponseForbidden(
render_to_string("wiki/permission_denied.html", context={'article': article, 'urlpath': urlpath},
request=request))
def get_article(func=None, can_read=True, can_write=False,
deleted_contents=False, not_locked=False,
......@@ -75,8 +75,9 @@ def get_article(func=None, can_read=True, can_write=False,
parent = models.URLPath.get_by_path(path)
return redirect(reverse("wiki:create", kwargs={'path': parent.path,}) + "?slug=%s" % pathlist[-1])
except models.URLPath.DoesNotExist:
c = RequestContext(request, {'error_type' : 'ancestors_missing'})
return HttpResponseNotFound(render_to_string("wiki/error.html", context_instance=c))
return HttpResponseNotFound(
render_to_string("wiki/error.html", context={'error_type': 'ancestors_missing'},
request=request))
if urlpath.article:
# urlpath is already smart about prefetching items on article (like current_revision), so we don't have to
article = urlpath.article
......
......@@ -4,9 +4,11 @@ from django.utils.encoding import force_unicode
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
from wiki.core.compat import BuildAttrsCompat
from wiki.editors.base import BaseEditor
class MarkItUpAdminWidget(forms.Widget):
class MarkItUpAdminWidget(BuildAttrsCompat, forms.Widget):
"""A simplified more fail-safe widget for the backend"""
def __init__(self, attrs=None):
# The 'rows' and 'cols' attributes are required for HTML correctness.
......@@ -18,11 +20,12 @@ class MarkItUpAdminWidget(forms.Widget):
def render(self, name, value, attrs=None):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, name=name)
final_attrs = self.build_attrs_compat(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
conditional_escape(force_unicode(value))))
class MarkItUpWidget(forms.Widget):
class MarkItUpWidget(BuildAttrsCompat, forms.Widget):
def __init__(self, attrs=None):
# The 'rows' and 'cols' attributes are required for HTML correctness.
default_attrs = {'class': 'markItUp',
......@@ -33,7 +36,7 @@ class MarkItUpWidget(forms.Widget):
def render(self, name, value, attrs=None):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, name=name)
final_attrs = self.build_attrs_compat(attrs, name=name)
return mark_safe(u'<div><textarea%s>%s</textarea></div>' % (flatatt(final_attrs),
conditional_escape(force_unicode(value))))
......
......@@ -16,6 +16,7 @@ from django.forms.widgets import HiddenInput
from wiki.core.plugins.base import PluginSettingsFormMixin
from django.contrib.auth.models import User
from wiki.core import permissions
from wiki.core.compat import BuildAttrsCompat
class SpamProtectionMixin():
......@@ -100,7 +101,7 @@ class EditForm(forms.Form):
return cd
class SelectWidgetBootstrap(forms.Select):
class SelectWidgetBootstrap(BuildAttrsCompat, forms.Select):
"""
http://twitter.github.com/bootstrap/components.html#buttonDropdowns
Needs bootstrap and jquery
......@@ -143,7 +144,7 @@ class SelectWidgetBootstrap(forms.Select):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, name=name)
final_attrs = self.build_attrs_compat(attrs, name=name)
output = ["""<div%(attrs)s>"""
""" <button class="btn btn-group-label" type="button">%(label)s</button>"""
""" <button class="btn dropdown-toggle" type="button" data-toggle="dropdown">"""
......
......@@ -2,11 +2,12 @@
from django.conf import settings as django_settings
from django.core.exceptions import ImproperlyConfigured
import warnings
from six import string_types, text_type
# TODO: Don't use wildcards
from article import *
from urlpath import *
from django.utils.functional import lazy
# TODO: Should the below stuff be executed a more logical place?
......@@ -29,8 +30,24 @@ if not 'django.contrib.humanize' in django_settings.INSTALLED_APPS:
if not 'django.contrib.contenttypes' in django_settings.INSTALLED_APPS:
raise ImproperlyConfigured('django-wiki: needs django.contrib.contenttypes in INSTALLED_APPS')
if not 'django.contrib.auth.context_processors.auth' in django_settings.TEMPLATE_CONTEXT_PROCESSORS:
raise ImproperlyConfigured('django-wiki: needs django.contrib.auth.context_processors.auth in TEMPLATE_CONTEXT_PROCESSORS')
# Need to handle Django 1.8 'TEMPLATES', recognizing that users may still be
# using 1.7 conventions/settings with 1.8.
TEMPLATE_CONTEXT_PROCESSORS = getattr(django_settings, 'TEMPLATE_CONTEXT_PROCESSORS', [])
if hasattr(django_settings, 'TEMPLATES'):
# Django 1.8 compat
backends = [b for b in django_settings.TEMPLATES if
b.get('BACKEND', '') == 'django.template.backends.django.DjangoTemplates']
if len(backends) == 1:
TEMPLATE_CONTEXT_PROCESSORS = backends[0].get('OPTIONS', {}).get('context_processors', [])
if 'django.contrib.auth.context_processors.auth' not in TEMPLATE_CONTEXT_PROCESSORS:
raise ImproperlyConfigured(
'django-wiki: needs django.contrib.auth.context_processors.auth in TEMPLATE_CONTEXT_PROCESSORS')
if not any(s in TEMPLATE_CONTEXT_PROCESSORS for s in ['django.core.context_processors.request',
'django.template.context_processors.request']):
raise ImproperlyConfigured(
'django-wiki: needs django.core.context_processors.request or django.template.context_processors.request in TEMPLATE_CONTEXT_PROCESSORS')
######################
......@@ -56,7 +73,7 @@ def reverse(*args, **kwargs):
return the result of calling reverse._transform_url(reversed_url)
for every url in the wiki namespace.
"""
if isinstance(args[0], basestring) and args[0].startswith('wiki:'):
if isinstance(args[0], string_types) and args[0].startswith('wiki:'):
url_kwargs = kwargs.get('kwargs', {})
path = url_kwargs.get('path', False)
# If a path is supplied then discard the article_id
......@@ -72,6 +89,23 @@ def reverse(*args, **kwargs):
url = original_django_reverse(*args, **kwargs)
return url
# Now we redefine reverse method
urlresolvers.reverse = reverse
\ No newline at end of file
reverse_lazy = lazy(reverse, text_type)
urlresolvers.reverse = reverse
urlresolvers.reverse_lazy = reverse_lazy
# Patch up other locations of the reverse function
try:
from django.urls import base
from django import urls
from django import shortcuts
base.reverse = reverse
base.reverse_lazy = reverse_lazy
urls.reverse = reverse
urls.reverse_lazy = reverse_lazy
shortcuts.reverse = reverse
except ImportError:
pass
......@@ -169,7 +169,6 @@ class Article(models.Model):
return _(u'Article without content (%(id)d)') % {'id': self.id}
class Meta:
app_label = settings.APP_LABEL
permissions = (
("moderate", "Can edit all articles and lock/unlock/restore"),
("assign", "Can change ownership of any article"),
......@@ -203,7 +202,6 @@ class ArticleForObject(models.Model):
is_mptt = models.BooleanField(default=False, editable=False)
class Meta:
app_label = settings.APP_LABEL
verbose_name = _(u'Article for object')
verbose_name_plural = _(u'Articles for object')
# Do not allow several objects
......@@ -311,7 +309,6 @@ class ArticleRevision(BaseRevisionMixin, models.Model):
self.article.save()
class Meta:
app_label = settings.APP_LABEL
get_latest_by = 'revision_number'
ordering = ('created',)
unique_together = ('article', 'revision_number')
......
......@@ -27,7 +27,6 @@ There are three kinds of plugin base models:
from article import Article, ArticleRevision
from wiki.conf import settings
class ArticlePlugin(models.Model):
"""This is the mother of all plugins. Extending from it means a deletion
......@@ -55,10 +54,8 @@ class ArticlePlugin(models.Model):
def purge(self):
"""Remove related contents completely, ie. media files."""
pass
class Meta:
app_label = settings.APP_LABEL
class ReusablePlugin(ArticlePlugin):
"""Extend from this model if you have a plugin that may be related to many
articles. Please note that the ArticlePlugin.article ForeignKey STAYS! This
......@@ -101,9 +98,7 @@ class ReusablePlugin(ArticlePlugin):
self.article = articles[0]
super(ReusablePlugin, self).save(*args, **kwargs)
class Meta:
app_label = settings.APP_LABEL
class SimplePluginCreateError(Exception): pass
......@@ -148,9 +143,7 @@ class SimplePlugin(ArticlePlugin):
self.article_revision = new_revision
super(SimplePlugin, self).save(*args, **kwargs)
class Meta:
app_label = settings.APP_LABEL
class RevisionPlugin(ArticlePlugin):
"""
......@@ -188,8 +181,6 @@ class RevisionPlugin(ArticlePlugin):
self.current_revision = new_revision
if save: self.save()
class Meta:
app_label = settings.APP_LABEL
class RevisionPluginRevision(BaseRevisionMixin, models.Model):
......@@ -226,7 +217,6 @@ class RevisionPluginRevision(BaseRevisionMixin, models.Model):
self.plugin.save()
class Meta:
app_label = settings.APP_LABEL
get_latest_by = 'revision_number'
ordering = ('-created',)
......
......@@ -33,7 +33,6 @@ class URLPath(MPTTModel):
INHERIT_PERMISSIONS = True
objects = managers.URLPathManager()
_default_manager = objects
articles = fields.GenericRelation(ArticleForObject)
......@@ -148,7 +147,6 @@ class URLPath(MPTTModel):
verbose_name = _(u'URL path')
verbose_name_plural = _(u'URL paths')
unique_together = ('site', 'parent', 'slug')
app_label = settings.APP_LABEL
def clean(self, *args, **kwargs):
if self.slug and not self.parent:
......
......@@ -35,7 +35,6 @@ class Attachment(ReusablePlugin):
class Meta:
verbose_name = _(u'attachment')
verbose_name_plural = _(u'attachments')
app_label = settings.APP_LABEL
def __unicode__(self):
return "%s: %s" % (self.article.current_revision.title, self.original_filename)
......@@ -86,7 +85,6 @@ class AttachmentRevision(BaseRevisionMixin, models.Model):
verbose_name_plural = _(u'attachment revisions')
ordering = ('created',)
get_latest_by = 'revision_number'
app_label = settings.APP_LABEL
def get_filename(self):
"""Used to retrieve the filename of a revision.
......
from django.conf import settings as django_settings
APP_LABEL = 'wiki'
SLUG = "attachments"
# Allow anonymous users to upload (not nice on an open network)
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Delete" %} "{{ attachment.current_revision.get_filename }}"{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "History of" %} "{{ attachment.current_revision.get_filename }}"{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Attachments" %}: {{ article.current_revision.title }}{% endblock %}
......@@ -32,7 +31,7 @@
<p>
{% if not attachment.current_revision.deleted %}
<a href="{% url 'wiki:attachments_replace' path=urlpath.path article_id=article.id attachment_id=attachment.id %}" class="btn">{% trans "Replace" %}</a>
{% if attachment.article = article %}
{% if 'attachment.article = article' %}
<a href="{% url 'wiki:attachments_delete' path=urlpath.path article_id=article.id attachment_id=attachment.id %}" class="btn">{% trans "Delete" %}</a>
{% else %}
<a href="{% url 'wiki:attachments_delete' path=urlpath.path article_id=article.id attachment_id=attachment.id %}" class="btn">{% trans "Detach" %}</a>
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Replace" %} "{{ attachment.current_revision.get_filename }}"{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Add file to" %} "{{ article.current_revision.title }}"{% endblock %}
......
......@@ -55,6 +55,11 @@ class AttachmentView(ArticleMixin, FormView):
return redirect("wiki:attachments_index", path=self.urlpath.path, article_id=self.article.id)
def get_context_data(self, **kwargs):
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs['attachments'] = self.attachments
kwargs['search_form'] = forms.SearchForm()
kwargs['selected_tab'] = 'attachments'
......@@ -127,6 +132,8 @@ class AttachmentReplaceView(ArticleMixin, FormView):
return {'description': self.attachment.current_revision.description}
def get_context_data(self, **kwargs):
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs['attachment'] = self.attachment
kwargs['selected_tab'] = 'attachments'
return super(AttachmentReplaceView, self).get_context_data(**kwargs)
......@@ -178,6 +185,8 @@ class AttachmentChangeRevisionView(ArticleMixin, View):
def get_context_data(self, **kwargs):
kwargs['selected_tab'] = 'attachments'
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
return ArticleMixin.get_context_data(self, **kwargs)
class AttachmentAddView(ArticleMixin, View):
......@@ -231,6 +240,8 @@ class AttachmentDeleteView(ArticleMixin, FormView):
def get_context_data(self, **kwargs):
kwargs['attachment'] = self.attachment
kwargs['selected_tab'] = 'attachments'
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
return super(AttachmentDeleteView, self).get_context_data(**kwargs)
......@@ -265,4 +276,6 @@ class AttachmentSearchView(ArticleMixin, ListView):
kwargs.update(kwargs_article)
kwargs.update(kwargs_listview)
kwargs['selected_tab'] = 'attachments'
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
return kwargs
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry
......@@ -15,7 +15,7 @@ class AttachmentPlugin(BasePlugin):
#settings_form = 'wiki.plugins.notifications.forms.SubscriptionForm'
slug = settings.SLUG
urlpatterns = patterns('',
urlpatterns = [
url(r'^$', views.AttachmentView.as_view(), name='attachments_index'),
url(r'^search/$', views.AttachmentSearchView.as_view(), name='attachments_search'),
url(r'^add/(?P<attachment_id>\d+)/$', views.AttachmentAddView.as_view(), name='attachments_add'),
......@@ -25,7 +25,7 @@ class AttachmentPlugin(BasePlugin):
url(r'^delete/(?P<attachment_id>\d+)/$', views.AttachmentDeleteView.as_view(), name='attachments_delete'),
url(r'^download/(?P<attachment_id>\d+)/revision/(?P<revision_id>\d+)/$', views.AttachmentDownloadView.as_view(), name='attachments_download'),
url(r'^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_view = views.AttachmentView().dispatch
......
# -*- coding: utf-8 -*-
from django.conf.urls import patterns
from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry
......@@ -8,7 +7,7 @@ from wiki.core.plugins.base import BasePlugin
class HelpPlugin(BasePlugin):
slug = 'help'
urlpatterns = patterns('',)
urlpatterns = []
sidebar = {'headline': _('Help'),
'icon_class': 'icon-question-sign',
......
......@@ -45,12 +45,16 @@ class ImagePreprocessor(markdown.preprocessors.Preprocessor):
caption_lines.append(line[4:])
line = None
else:
html = render_to_string("wiki/plugins/images/render.html",
Context({'image': image,
'caption': article_markdown("\n".join(caption_lines),
self.markdown.article,
extensions=self.markdown.registeredExtensions),
'align': alignment}))
html = render_to_string(
"wiki/plugins/images/render.html",
context={
'image': image,
'caption': article_markdown("\n".join(caption_lines),
self.markdown.article,
extensions=self.markdown.registeredExtensions),
'align': alignment
}
)
line = html + line
previous_line_was_image = False
if not line is None:
......
......@@ -39,7 +39,6 @@ class Image(RevisionPlugin):
class Meta:
verbose_name = _(u'image')
verbose_name_plural = _(u'images')
app_label = settings.APP_LABEL
def __unicode__(self):
title = (_(u'Image: %s') % self.current_revision.imagerevision.get_filename()) if self.current_revision else _(u'Current revision not set!!')
......@@ -91,7 +90,6 @@ class ImageRevision(RevisionPluginRevision):
class Meta:
verbose_name = _(u'image revision')
verbose_name_plural = _(u'image revisions')
app_label = settings.APP_LABEL
ordering = ('-created',)
def __unicode__(self):
......
......@@ -12,5 +12,3 @@ IMAGE_PATH_OBSCURIFY = getattr(django_settings, 'WIKI_IMAGE_PATH_OBSCURIFY', Tru
ANONYMOUS = getattr(django_settings, 'WIKI_ATTACHMENTS_ANONYMOUS', False)
SLUG = 'images'
APP_LABEL = 'wiki'
\ No newline at end of file
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize thumbnail %}
{% load url from future %}
{% block pagetitle %}{% trans "Images" %}: {{ article.current_revision.title }}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize thumbnail %}
{% load url from future %}
{% block pagetitle %}{% trans "Purge deletion" %}: {{ image }}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize thumbnail %}
{% load url from future %}
{% block pagetitle %}{% trans "Replace image" %}: {{ image }}{% endblock %}
......
{% load i18n wiki_tags wiki_images_tags humanize thumbnail %}
{% load url from future %}
<script type="text/javascript">
function insert_image(image_id) {
......
......@@ -92,6 +92,10 @@ class PurgeView(ArticleMixin, FormView):
return redirect('wiki:images_index', article_id=self.article_id)
def get_context_data(self, **kwargs):
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs = ArticleMixin.get_context_data(self, **kwargs)
kwargs.update(FormView.get_context_data(self, **kwargs))
return kwargs
......@@ -141,6 +145,10 @@ class RevisionAddView(ArticleMixin, FormView):
return kwargs
def get_context_data(self, **kwargs):
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs = super(RevisionAddView, self).get_context_data(**kwargs)
kwargs['image'] = self.image
return kwargs
......
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from wiki.core.plugins import registry
......@@ -39,15 +39,15 @@ class ImagePlugin(BasePlugin):
css = {
'screen': 'wiki/colorbox/example1/colorbox.css'
}
urlpatterns = patterns('',
urlpatterns = [
url('^$', views.ImageView.as_view(), name='images_index'),
url('^delete/(?P<image_id>\d+)/$', views.DeleteView.as_view(), name='images_delete'),
url('^restore/(?P<image_id>\d+)/$', views.DeleteView.as_view(), name='images_restore', kwargs={'restore': True}),
url('^purge/(?P<image_id>\d+)/$', views.PurgeView.as_view(), name='images_purge'),
url('^(?P<image_id>\d+)/revision/change/(?P<rev_id>\d+)/$', views.RevisionChangeView.as_view(), name='images_restore'),
url('^(?P<image_id>\d+)/revision/add/$', views.RevisionAddView.as_view(), name='images_add_revision'),
)
]
markdown_extensions = [ImageExtension()]
......
......@@ -95,6 +95,8 @@ class UrlizeExtension(markdown.Extension):
md.inlinePatterns['autolink'] = UrlizePattern(URLIZE_RE, md)
def makeExtension(configs=None):
if configs is None:
configs = {}
return UrlizeExtension(configs=configs)
if __name__ == "__main__":
......
{% load i18n %}
{% load url from future %}
<h4>{% trans "Link to another wiki page" %}</h4>
<p>
......
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from wiki.conf import settings
......@@ -13,9 +13,9 @@ from django.core.urlresolvers import reverse_lazy
class LinkPlugin(BasePlugin):
slug = 'links'
urlpatterns = patterns('',
urlpatterns = [
url(r'^json/query-urlpath/$', views.QueryUrlPath.as_view(), name='links_query_urlpath'),
)
]
sidebar = {'headline': _('Links'),
'icon_class': 'icon-bookmark',
......
......@@ -3,8 +3,7 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.db.models import signals
from django_notify import notify
from django_notify.models import Subscription
from django_notify.models import notify, Subscription
from wiki import models as wiki_models
from wiki.models.pluginbase import ArticlePlugin
......@@ -19,10 +18,7 @@ class ArticleSubscription(ArticlePlugin, Subscription):
{'user': self.settings.user.username,
'article': self.article.current_revision.title,
'type': self.notification_type.label})
class Meta:
app_label = settings.APP_LABEL
def default_url(article, urlpath=None):
try:
......
#from django.conf import settings as django_settings
APP_LABEL = 'wiki'
\ No newline at end of file
{% extends "wiki/base.html" %}
{% load i18n wiki_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Log in" %}{% endblock %}
{% block wiki_contents %}
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{{ article.current_revision.title }}{% endblock %}
......
{% load sekizai_tags i18n %}{% load url from future %}<!DOCTYPE html>
{% load sekizai_tags i18n %}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Add new article" %}{% endblock %}
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Delete article" %}{% endblock %}
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Article deleted" %}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Listing articles in" %} {{ article.current_revision.title }}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{% trans "Edit" %}: {{ article.current_revision.title }}{% endblock %}
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{{ article.current_revision.title }}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "History" %}: {{ article.current_revision.title }}{% endblock %}
......
{% load i18n %}
{% load url from future %}
<em>
{% url 'wiki:signup' as signup_url %}
{% url 'wiki:login' as login_url %}
......
{% load i18n wiki_tags %}{% load url from future %}
{% load i18n wiki_tags %}
{% with selected_tab as selected %}
......
{% load i18n %}{% load url from future %}
{% load i18n %}
{% if urlpath %}
<div id="article-breadcrumbs">
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}Permission Denied{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{% trans "Settings" %}: {{ article.current_revision.title }}{% endblock %}
......
{% extends "wiki/article.html" %}
{% load wiki_tags i18n humanize %}
{% load url from future %}
{% block pagetitle %}{% trans "Source of" %} {{ article.current_revision.title }}{% endblock %}
......
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from wiki.views import article, accounts
from wiki.conf import settings
from wiki.core.plugins import registry
urlpatterns = patterns('',
url('^$', article.ArticleView.as_view(), name='root', kwargs={'path': ''}),
url('^create-root/$', 'wiki.views.article.root_create', name='root_create'),
url('^_revision/diff/(?P<revision_id>\d+)/$', 'wiki.views.article.diff', name='diff'),
)
urlpatterns = [
url(r'^$', article.ArticleView.as_view(), name='root', kwargs={'path': ''}),
url(r'^create-root/$', article.root_create, name='root_create'),
url(r'^_revision/diff/(?P<revision_id>\d+)/$', article.diff, name='diff'),
]
if settings.ACCOUNT_HANDLING:
urlpatterns += patterns('',
url('^_accounts/sign-up/$', accounts.Signup.as_view(), name='signup'),
url('^_accounts/logout/$', accounts.Logout.as_view(), name='logout'),
url('^_accounts/login/$', accounts.Login.as_view(), name='login'),
)
urlpatterns += [
url(r'^_accounts/sign-up/$', accounts.Signup.as_view(), name='signup'),
url(r'^_accounts/logout/$', accounts.Logout.as_view(), name='logout'),
url(r'^_accounts/login/$', accounts.Login.as_view(), name='login'),
]
urlpatterns += patterns('',
urlpatterns += [
# 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.article.change_revision', name='change_revision'),
url('^_revision/preview/(?P<article_id>\d+)/$', article.Preview.as_view(), 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(r'^_revision/change/(?P<article_id>\d+)/(?P<revision_id>\d+)/$', article.change_revision,
name='change_revision'),
url(r'^_revision/preview/(?P<article_id>\d+)/$', article.Preview.as_view(), name='preview_revision'),
url(r'^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', article.merge,
name='merge_revision_preview', kwargs={'preview': True}),
# Paths decided by article_ids
url('^(?P<article_id>\d+)/$', article.ArticleView.as_view(), name='get'),
url('^(?P<article_id>\d+)/delete/$', article.Delete.as_view(), name='delete'),
url('^(?P<article_id>\d+)/deleted/$', article.Deleted.as_view(), name='deleted'),
url('^(?P<article_id>\d+)/edit/$', article.Edit.as_view(), name='edit'),
url('^(?P<article_id>\d+)/preview/$', article.Preview.as_view(), name='preview'),
url('^(?P<article_id>\d+)/history/$', article.History.as_view(), name='history'),
url('^(?P<article_id>\d+)/settings/$', article.Settings.as_view(), name='settings'),
url('^(?P<article_id>\d+)/source/$', article.Source.as_view(), name='source'),
url('^(?P<article_id>\d+)/revision/change/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
url('^(?P<article_id>\d+)/revision/merge/(?P<revision_id>\d+)/$', 'wiki.views.article.merge', name='merge_revision'),
url('^(?P<article_id>\d+)/plugin/(?P<slug>\w+)/$', article.Plugin.as_view(), name='plugin'),
)
url(r'^(?P<article_id>\d+)/$', article.ArticleView.as_view(), name='get'),
url(r'^(?P<article_id>\d+)/delete/$', article.Delete.as_view(), name='delete'),
url(r'^(?P<article_id>\d+)/deleted/$', article.Deleted.as_view(), name='deleted'),
url(r'^(?P<article_id>\d+)/edit/$', article.Edit.as_view(), name='edit'),
url(r'^(?P<article_id>\d+)/preview/$', article.Preview.as_view(), name='preview'),
url(r'^(?P<article_id>\d+)/history/$', article.History.as_view(), name='history'),
url(r'^(?P<article_id>\d+)/settings/$', article.Settings.as_view(), name='settings'),
url(r'^(?P<article_id>\d+)/source/$', article.Source.as_view(), name='source'),
url(r'^(?P<article_id>\d+)/revision/change/(?P<revision_id>\d+)/$', article.change_revision,
name='change_revision'),
url(r'^(?P<article_id>\d+)/revision/merge/(?P<revision_id>\d+)/$', article.merge, name='merge_revision'),
url(r'^(?P<article_id>\d+)/plugin/(?P<slug>\w+)/$', article.Plugin.as_view(), name='plugin'),
]
for plugin in registry.get_plugins().values():
slug = getattr(plugin, 'slug', None)
plugin_urlpatterns = getattr(plugin, 'urlpatterns', None)
if slug and plugin_urlpatterns:
urlpatterns += patterns('',
url('^(?P<article_id>\d+)/plugin/'+slug+'/', include(plugin_urlpatterns)),
url('^(?P<path>.+/|)_plugin/'+slug+'/', include(plugin_urlpatterns)),
)
urlpatterns += [
url(r'^(?P<article_id>\d+)/plugin/' + slug + '/', include(plugin_urlpatterns)),
url(r'^(?P<path>.+/|)_plugin/' + slug + '/', include(plugin_urlpatterns)),
]
urlpatterns += patterns('',
urlpatterns += [
# Paths decided by URLs
url('^(?P<path>.+/|)_create/$', article.Create.as_view(), name='create'),
url('^(?P<path>.+/|)_delete/$', article.Delete.as_view(), name='delete'),
url('^(?P<path>.+/|)_deleted/$', article.Deleted.as_view(), name='deleted'),
url('^(?P<path>.+/|)_edit/$', article.Edit.as_view(), name='edit'),
url('^(?P<path>.+/|)_preview/$', article.Preview.as_view(), name='preview'),
url('^(?P<path>.+/|)_history/$', article.History.as_view(), name='history'),
url('^(?P<path>.+/|)_dir/$', article.Dir.as_view(), name='dir'),
url('^(?P<path>.+/|)_settings/$', article.Settings.as_view(), name='settings'),
url('^(?P<path>.+/|)_source/$', article.Source.as_view(), name='source'),
url('^(?P<path>.+/|)_revision/change/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
url('^(?P<path>.+/|)_revision/merge/(?P<revision_id>\d+)/$', 'wiki.views.article.merge', name='merge_revision'),
url('^(?P<path>.+/|)_plugin/(?P<slug>\w+)/$', article.Plugin.as_view(), name='plugin'),
url('^(?P<path>.+/|)$', article.ArticleView.as_view(), name='get'),
)
url(r'^(?P<path>.+/|)_create/$', article.Create.as_view(), name='create'),
url(r'^(?P<path>.+/|)_delete/$', article.Delete.as_view(), name='delete'),
url(r'^(?P<path>.+/|)_deleted/$', article.Deleted.as_view(), name='deleted'),
url(r'^(?P<path>.+/|)_edit/$', article.Edit.as_view(), name='edit'),
url(r'^(?P<path>.+/|)_preview/$', article.Preview.as_view(), name='preview'),
url(r'^(?P<path>.+/|)_history/$', article.History.as_view(), name='history'),
url(r'^(?P<path>.+/|)_dir/$', article.Dir.as_view(), name='dir'),
url(r'^(?P<path>.+/|)_settings/$', article.Settings.as_view(), name='settings'),
url(r'^(?P<path>.+/|)_source/$', article.Source.as_view(), name='source'),
url(r'^(?P<path>.+/|)_revision/change/(?P<revision_id>\d+)/$', article.change_revision, name='change_revision'),
url(r'^(?P<path>.+/|)_revision/merge/(?P<revision_id>\d+)/$', article.merge, name='merge_revision'),
url(r'^(?P<path>.+/|)_plugin/(?P<slug>\w+)/$', article.Plugin.as_view(), name='plugin'),
url(r'^(?P<path>.+/|)$', article.ArticleView.as_view(), name='get'),
]
def get_pattern(app_name="wiki", namespace="wiki"):
"""Every url resolution takes place as "wiki:view_name".
......
......@@ -43,11 +43,13 @@ class Create(FormView, ArticleMixin):
@method_decorator(get_article(can_write=True))
def dispatch(self, 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=None):
"""
Returns an instance of the form to be used in this view.
"""
if form_class is None:
form_class = self.get_form_class()
kwargs = self.get_form_kwargs()
initial = kwargs.get('initial', {})
initial['slug'] = self.request.GET.get('slug', None)
......@@ -99,11 +101,16 @@ class Create(FormView, ArticleMixin):
return redirect('wiki:get', self.newpath.path)
def get_context_data(self, **kwargs):
kwargs['parent_urlpath'] = self.urlpath
kwargs['parent_article'] = self.article
kwargs['create_form'] = kwargs.pop('form', None)
kwargs['editor'] = editors.getEditor()
return super(Create, self).get_context_data(**kwargs)
c = ArticleMixin.get_context_data(self, **kwargs)
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in c:
c['form'] = self.get_form()
c['parent_urlpath'] = self.urlpath
c['parent_article'] = self.article
c['create_form'] = c.pop('form', None)
c['editor'] = editors.getEditor()
return c
class Delete(FormView, ArticleMixin):
......@@ -140,9 +147,9 @@ class Delete(FormView, ArticleMixin):
def get_initial(self):
return {'revision': self.article.current_revision}
def get_form(self, form_class):
form = super(Delete, self).get_form(form_class)
def get_form(self, form_class=None):
form = super(Delete, self).get_form(form_class=form_class)
if self.article.can_moderate(self.request.user):
form.fields['purge'].widget = forms.forms.CheckboxInput()
return form
......@@ -193,7 +200,11 @@ class Delete(FormView, ArticleMixin):
cannot_delete_children = False
if self.children_slice and not self.article.can_moderate(self.request.user):
cannot_delete_children = True
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs['delete_form'] = kwargs.pop('form', None)
kwargs['cannot_delete_root'] = self.cannot_delete_root
kwargs['delete_children'] = self.children_slice[:20]
......@@ -202,7 +213,7 @@ class Delete(FormView, ArticleMixin):
return super(Delete, self).get_context_data(**kwargs)
class Edit(FormView, ArticleMixin):
class Edit(ArticleMixin, FormView):
"""Edit an article and process sidebar plugins."""
form_class = forms.EditForm
......@@ -213,12 +224,14 @@ class Edit(FormView, ArticleMixin):
self.sidebar_plugins = plugin_registry.get_sidebar()
self.sidebar = []
return super(Edit, self).dispatch(request, article, *args, **kwargs)
def get_form(self, form_class):
def get_form(self, form_class=None):
"""
Checks from querystring data that the edit form is actually being saved,
otherwise removes the 'data' and 'files' kwargs from form initialisation.
"""
if form_class is None:
form_class = self.get_form_class()
kwargs = self.get_form_kwargs()
if self.request.POST.get('save', '') != '1' and self.request.POST.get('preview') != '1':
kwargs['data'] = None
......@@ -283,7 +296,7 @@ class Edit(FormView, ArticleMixin):
revision.deleted = False
revision.set_from_request(self.request)
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 successfully added.'))
return self.get_success_url()
def get_success_url(self):
......@@ -293,7 +306,11 @@ class Edit(FormView, ArticleMixin):
return redirect('wiki:get', article_id=self.article.id)
def get_context_data(self, **kwargs):
kwargs['edit_form'] = kwargs.pop('form', None)
# Needed for Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs['edit_form'] = kwargs['form']
kwargs['editor'] = editors.getEditor()
kwargs['selected_tab'] = 'edit'
kwargs['sidebar'] = self.sidebar
......@@ -350,11 +367,11 @@ class Deleted(Delete):
return {'revision': self.article.current_revision,
'purge': True}
def get_form(self, form_class):
form = super(Delete, self).get_form(form_class)
return form
def get_context_data(self, **kwargs):
# Needed since Django 1.9 because get_context_data is no longer called
# with the form instance
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
kwargs['purge_form'] = kwargs.pop('form', None)
return super(Delete, 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