Merge branch 'master' of github.com:torchbox/wagtail

pull/3/head
Matt Westcott 2014-02-06 14:31:42 +00:00
commit a61a829c89
98 zmienionych plików z 551 dodań i 355 usunięć

Wyświetl plik

@ -1,3 +1,10 @@
import copy
import re
import datetime
from taggit.forms import TagWidget
from modelcluster.forms import ClusterForm, ClusterFormMetaclass
from django.template.loader import render_to_string
from django.template.defaultfilters import addslashes
from django.utils.safestring import mark_safe
@ -8,16 +15,9 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured, ValidationError
from django.core.urlresolvers import reverse
import copy
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.util import camelcase_to_underscore
from wagtail.wagtailcore.fields import RichTextArea
from modelcluster.forms import ClusterForm, ClusterFormMetaclass
from taggit.forms import TagWidget
import re
import datetime
class FriendlyDateInput(forms.DateInput):
@ -135,8 +135,10 @@ WagtailAdminModelForm = WagtailAdminModelFormMetaclass('WagtailAdminModelForm',
# the nice form fields defined in FORM_FIELD_OVERRIDES.
def get_form_for_model(model, fields=None, exclude=None, formsets=None, exclude_formsets=None,
widgets=None):
def get_form_for_model(
model,
fields=None, exclude=None, formsets=None, exclude_formsets=None, widgets=None
):
# django's modelform_factory with a bit of custom behaviour
# (dealing with Treebeard's tree-related fields that really should have
@ -216,10 +218,12 @@ class EditHandler(object):
# the top-level edit handler is responsible for providing a form class that can produce forms
# acceptable to the edit handler
_form_class = None
@classmethod
def get_form_class(cls, model):
if cls._form_class is None:
cls._form_class = get_form_for_model(model,
cls._form_class = get_form_for_model(
model,
formsets=cls.required_formsets(), widgets=cls.widget_overrides())
return cls._form_class
@ -232,7 +236,6 @@ class EditHandler(object):
raise ValueError("EditHandler did not receive a form object")
self.form = form
# Heading / help text to display to the user
heading = ""
help_text = ""
@ -251,7 +254,6 @@ class EditHandler(object):
"""
return ""
def field_type(self):
"""
The kind of field it is e.g boolean_field. Useful for better semantic markup of field display based on type
@ -315,6 +317,7 @@ class BaseCompositeEditHandler(EditHandler):
Concrete subclasses must attach a 'children' property
"""
_widget_overrides = None
@classmethod
def widget_overrides(cls):
if cls._widget_overrides is None:
@ -327,6 +330,7 @@ class BaseCompositeEditHandler(EditHandler):
return cls._widget_overrides
_required_formsets = None
@classmethod
def required_formsets(cls):
if cls._required_formsets is None:
@ -360,9 +364,11 @@ class BaseCompositeEditHandler(EditHandler):
return result
class BaseTabbedInterface(BaseCompositeEditHandler):
template = "wagtailadmin/edit_handlers/tabbed_interface.html"
def TabbedInterface(children):
return type('_TabbedInterface', (BaseTabbedInterface,), {'children': children})
@ -370,6 +376,7 @@ def TabbedInterface(children):
class BaseObjectList(BaseCompositeEditHandler):
template = "wagtailadmin/edit_handlers/object_list.html"
def ObjectList(children, heading=""):
return type('_ObjectList', (BaseObjectList,), {
'children': children,
@ -380,6 +387,7 @@ def ObjectList(children, heading=""):
class BaseMultiFieldPanel(BaseCompositeEditHandler):
template = "wagtailadmin/edit_handlers/multi_field_panel.html"
def MultiFieldPanel(children, heading=""):
return type('_MultiFieldPanel', (BaseMultiFieldPanel,), {
'children': children,
@ -402,7 +410,7 @@ class BaseFieldPanel(EditHandler):
return "single-field"
def field_type(self):
return camelcase_to_underscore(self.bound_field.field.__class__.__name__)
return camelcase_to_underscore(self.bound_field.field.__class__.__name__)
def field_classnames(self):
classname = self.field_type()
@ -414,11 +422,12 @@ class BaseFieldPanel(EditHandler):
return classname
object_template = "wagtailadmin/edit_handlers/field_panel_object.html"
def render_as_object(self):
return mark_safe(render_to_string(self.object_template, {
'self': self,
'field_content': self.render_as_field(show_help_text=False),
}))
}))
def render_js(self):
try:
@ -429,8 +438,8 @@ class BaseFieldPanel(EditHandler):
return mark_safe(js_func(self.bound_field.id_for_label))
field_template = "wagtailadmin/edit_handlers/field_panel_field.html"
def render_as_field(self, show_help_text=True):
return mark_safe(render_to_string(self.field_template, {
'field': self.bound_field,
@ -441,6 +450,7 @@ class BaseFieldPanel(EditHandler):
def rendered_fields(self):
return [self.field_name]
def FieldPanel(field_name, classname=None):
return type('_FieldPanel', (BaseFieldPanel,), {
'field_name': field_name,
@ -452,6 +462,7 @@ class BaseRichTextFieldPanel(BaseFieldPanel):
def render_js(self):
return mark_safe("makeRichTextEditable(fixPrefix('%s'));" % self.bound_field.id_for_label)
def RichTextFieldPanel(field_name):
return type('_RichTextFieldPanel', (BaseRichTextFieldPanel,), {
'field_name': field_name,
@ -498,11 +509,13 @@ class BaseChooserPanel(BaseFieldPanel):
def render_js(self):
return mark_safe("%s(fixPrefix('%s'));" % (self.js_function_name, self.bound_field.id_for_label))
class BasePageChooserPanel(BaseChooserPanel):
field_template = "wagtailadmin/edit_handlers/page_chooser_panel.html"
object_type_name = "page"
_target_content_type = None
@classmethod
def target_content_type(cls):
if cls._target_content_type is None:
@ -540,6 +553,7 @@ class BasePageChooserPanel(BaseChooserPanel):
(parent.id if parent else 'null'),
))
def PageChooserPanel(field_name, page_type=None):
return type('_PageChooserPanel', (BasePageChooserPanel,), {
'field_name': field_name,
@ -558,6 +572,7 @@ class BaseInlinePanel(EditHandler):
return extract_panel_definitions_from_model_class(cls.related.model, exclude=[cls.related.field.name])
_child_edit_handler_class = None
@classmethod
def get_child_edit_handler_class(cls):
if cls._child_edit_handler_class is None:
@ -578,7 +593,6 @@ class BaseInlinePanel(EditHandler):
else:
return {}
def __init__(self, instance=None, form=None):
super(BaseInlinePanel, self).__init__(instance=instance, form=form)
@ -606,6 +620,7 @@ class BaseInlinePanel(EditHandler):
self.empty_child = child_edit_handler_class(instance=empty_form.instance, form=empty_form)
template = "wagtailadmin/edit_handlers/inline_panel.html"
def render(self):
return mark_safe(render_to_string(self.template, {
'self': self,
@ -613,12 +628,14 @@ class BaseInlinePanel(EditHandler):
}))
js_template = "wagtailadmin/edit_handlers/inline_panel.js"
def render_js(self):
return mark_safe(render_to_string(self.js_template, {
'self': self,
'can_order': self.formset.can_order,
}))
def InlinePanel(base_model, relation_name, panels=None, label='', help_text=''):
rel = getattr(base_model, relation_name).related
return type('_InlinePanel', (BaseInlinePanel,), {

Wyświetl plik

@ -2,6 +2,7 @@ from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm
class SearchForm(forms.Form):
def __init__(self, *args, **kwargs):
placeholder_suffix = kwargs.pop('placeholder_suffix', "")
@ -13,13 +14,16 @@ class SearchForm(forms.Form):
class ExternalLinkChooserForm(forms.Form):
url = forms.URLField(required=True)
class ExternalLinkChooserWithLinkTextForm(forms.Form):
url = forms.URLField(required=True)
link_text = forms.CharField(required=True)
class EmailLinkChooserForm(forms.Form):
email_address = forms.EmailField(required=True)
class EmailLinkChooserWithLinkTextForm(forms.Form):
email_address = forms.EmailField(required=True)
link_text = forms.CharField(required=False)
@ -54,9 +58,9 @@ class PasswordResetForm(PasswordResetForm):
if not found_non_ldap_user:
# All found users are LDAP users, give error message
raise forms.ValidationError("Sorry, you cannot reset your password here as your user account is managed by another server.")
raise forms.ValidationError("Sorry, you cannot reset your password here as your user account is managed by another server.")
else:
# No user accounts exist
raise forms.ValidationError("This email address is not recognised.")
return cleaned_data
return cleaned_data

Wyświetl plik

@ -8,12 +8,15 @@ _hooks = {}
# def construct_main_menu(menu_items):
# ...
def register(hook_name, fn):
if hook_name not in _hooks:
_hooks[hook_name] = []
_hooks[hook_name].append(fn)
_searched_for_hooks = False
def search_for_hooks():
global _searched_for_hooks
if not _searched_for_hooks:

Wyświetl plik

@ -1,6 +1,7 @@
from django.utils.text import slugify
from django.utils.html import format_html
class MenuItem(object):
def __init__(self, label, url, name=None, classnames='', order=1000):
self.label = label
@ -10,5 +11,6 @@ class MenuItem(object):
self.order = order
def render_html(self):
return format_html(u"""<li class="menu-{0}"><a href="{1}" class="{2}">{3}</a></li>""",
return format_html(
u"""<li class="menu-{0}"><a href="{1}" class="{2}">{3}</a></li>""",
self.name, self.url, self.classnames, self.label)

Wyświetl plik

@ -1,8 +1,9 @@
import json
from django.http import HttpResponse
from django.template import RequestContext
from django.template.loader import render_to_string
import json
def render_modal_workflow(request, html_template, js_template, template_vars={}):
""""

Wyświetl plik

@ -5,6 +5,21 @@
width:50px;
height:50px;
a{
position:absolute;
z-index:2;
left:0;
display:block;
width:100%;
height:50px;
}
img{
z-index:2;
position:relative;
.border-radius(100%);
border:0;
}
&:before{
.border-radius(100%);
color:@color-grey-3;
@ -19,23 +34,9 @@
z-index:1;
left:0;
}
a{
position:absolute;
z-index:2;
left:0;
display:block;
width:100%;
height:50px;
}
img{
z-index:2;
position:relative;
.border-radius(100%);
border:0;
}
&:hover:before{
color:@color-teal;
border-color:@color-teal;
color:@color-grey-3;
border-color:@color-grey-3;
}
&.small{

Wyświetl plik

@ -182,7 +182,8 @@ input[type=submit], input[type=reset], input[type=button], .button, button{
&.yes{
background-color: @color-button-yes;
border:1px solid @color-button-yes;
&.button-secondary{
border:1px solid @color-button-yes;
color:@color-button-yes;
@ -196,6 +197,7 @@ input[type=submit], input[type=reset], input[type=button], .button, button{
}
&.no, &.serious{
background-color: @color-button-no;
border:1px solid @color-button-no;
&.button-secondary{
border:1px solid @color-button-no;

Wyświetl plik

@ -116,7 +116,6 @@ ul.listing{
}
.status-tag{
border-color:white;
color:white;
}
}
@ -141,19 +140,16 @@ ul.listing{
}
.index {
color:white;
background-color:@color-header-bg;
background-color:@color-grey-4;
.title h2{
font-size:1.2em;
color:white;
opacity:1;
a{
.transition(opacity 0.2s ease);
}
a:hover{
opacity:0.7;
color:white;
}
}
a{
@ -167,13 +163,33 @@ ul.listing{
}
a{
color:white;
&:hover{
color:@color-teal-dark;
}
}
.button{
background-color:@color-teal-darker;
&:hover{
color:white;
background:@color-teal-dark;
}
}
}
.button{
background-color:@color-teal-darker;
&:hover{
background:@color-teal-dark;
}
.page-explorer & .index{
color:white;
background-color:@color-header-bg;
.title h2{
color:white;
a:hover{
color:white;
}
}
}
@ -466,10 +482,8 @@ ul.listing{
padding-left:50px;
}
}
}
/* Transitions */
.listing {
thead .dropdown ul{

Wyświetl plik

@ -1,8 +1,6 @@
.messages{
position:relative;
z-index:5;
background-color:@color-grey-5;
ul{

Wyświetl plik

@ -147,13 +147,9 @@ img{
#nav-toggle{
left:0%;
//margin-left:20px;
//.box-shadow(0px 0px 10px 5px rgba(255, 255, 255, 0.5));
cursor:pointer;
position:absolute;
//background: @color-grey-1;
width:40px;
//opacity:0.8;
&:before{
font-size:40px;
@ -360,9 +356,6 @@ body.nav-open .content-wrapper{
position:fixed;
}
body.nav-open #nav-toggle{
left:80%;
}
body.nav-open footer{
bottom:1px;
}
@ -560,11 +553,10 @@ footer{
position: absolute; right: -0.9em; top: 0;
z-index: 1;
}
&:before {
border-left: 1em solid @color-header-bg;
&:before {
border-left: 1em solid white;
position: absolute; left: 0; top: 0;
}
&:hover {
background: @color-teal-darker;
@ -596,7 +588,14 @@ footer{
}
}
}
}
}
header & li{
&:before {
border-left: 1em solid @color-header-bg;
position: absolute; left: 0; top: 0;
}
}
}
.row{
@ -744,17 +743,10 @@ footer, .logo{
margin:auto;
text-align:center;
margin-bottom:1em;
img{
border:2px solid white;
}
a{
padding:0 0 1em 0;
}
&:before{
color:@color-grey-2;
border: 2px solid @color-grey-2;
}
&:hover{
.box-shadow(0px 0px 6px 0px rgba(0,0,0,1));
}

Wyświetl plik

@ -40,7 +40,7 @@
@color-button-no: @color-red;
@color-button-no-hover: darken(@color-button-no, 20%);
@color-link: @color-teal;
@color-link-hover: darken(@color-button, 8%);
@color-link-hover: @color-teal-dark;
@color-text-base: @color-grey-2;
@color-text-input: @color-grey-1;

Wyświetl plik

@ -4,15 +4,15 @@ function addMessage(status,text){
var addMsgTimeout = setTimeout(function(){
$('.messages').addClass('appear');
clearTimeout(addMsgTimeout);
}, 100)
}, 100);
}
$(function(){
// Add class to the body from which transitions may be hung so they don't appear to transition as the page loads
$('body').addClass('ready');
$('body').addClass('ready');
// Enable toggle to open/close nav
$('#nav-toggle').click(function(){
$('#nav-toggle').click(function(){
$('body').toggleClass('nav-open');
if(!$('body').hasClass('nav-open')){
$('body').addClass('nav-closed');
@ -24,9 +24,9 @@ $(function(){
// Enable swishy section navigation menu
$('.explorer').addClass('dl-menuwrapper').dlmenu({
animationClasses : {
classin : 'dl-animate-in-2',
classin : 'dl-animate-in-2',
classout : 'dl-animate-out-2'
}
}
});
// Resize nav to fit height of window. This is an unimportant bell/whistle to make it look nice
@ -39,11 +39,11 @@ $(function(){
// $(this).css({'height':thisHeight - footerHeight, 'overflow-y':'scroll'});
// $('> ul', $(this)).height(thisHeight)
});
}
};
fitNav();
$(window).resize(function(){
fitNav();
})
});
// Apply auto-height sizing to text areas
// NB .richtext (hallo.js-enabled) divs do not need this as they expand to fit their content by default
@ -51,27 +51,26 @@ $(function(){
// Enable nice focus effects on all fields. This enables help text on hover.
$(document).on('focus mouseover', 'input,textarea,select', function(){
$(this).closest('.field').addClass('focused')
$(this).closest('fieldset').addClass('focused')
$(this).closest('li').addClass('focused')
})
$(this).closest('.field').addClass('focused');
$(this).closest('fieldset').addClass('focused');
$(this).closest('li').addClass('focused');
});
$(document).on('blur mouseout', 'input,textarea,select', function(){
$(this).closest('.field').removeClass('focused')
$(this).closest('fieldset').removeClass('focused')
$(this).closest('li').removeClass('focused')
$(this).closest('.field').removeClass('focused');
$(this).closest('fieldset').removeClass('focused');
$(this).closest('li').removeClass('focused');
});
/* tabs */
$(document).on('click', '.tab-nav a', function (e) {
e.preventDefault()
e.preventDefault();
$(this).tab('show');
});
});
$(document).on('click', '.tab-toggle', function(e){
e.preventDefault()
e.preventDefault();
$('.tab-nav a[href="'+ $(this).attr('href') +'"]').click();
})
});
$('.dropdown-toggle').bind('click', function(){
$(this).closest('.dropdown').toggleClass('open');
@ -85,13 +84,13 @@ $(function(){
if(!$(relTarg).hasClass('dropdown-toggle')){
$('.dropdown').removeClass('open');
}
})
});
/* Bulk-selection */
$(document).on('click', 'thead .bulk', function(){
$(this).closest('table').find('tbody .bulk input').each(function(){
$(this).prop('checked', !$(this).prop('checked'));
})
$(this).prop('checked', !$(this).prop('checked'));
});
});
$(".nav-main .more > a").bind('click keydown', function(){
@ -100,11 +99,11 @@ $(function(){
});
$('#menu-search input').bind('focus', function(){
$('#menu-search').addClass('focussed');
$('#menu-search').addClass('focussed');
}).bind('blur', function(){
$('#menu-search').removeClass('focussed');
})
});
$('#menu-search').bind('focus click', function(){
$(this).addClass('focussed');
})
})
});
});

Wyświetl plik

@ -5,7 +5,7 @@ possibly after several navigation steps
function ModalWorkflow(opts) {
/* options passed in 'opts':
'url' (required): initial
'url' (required): initial
'responses' (optional): dict of callbacks to be called when the modal content
calls modal.respond(callbackName, params)
*/

Wyświetl plik

@ -48,7 +48,7 @@ function insertRichTextDeleteControl(elem) {
$(elem).fadeOut(function() {
$(elem).remove();
});
})
});
}
function initDateChoosers(context) {
@ -156,11 +156,11 @@ function InlinePanel(opts) {
if (opts.canOrder) {
forms = self.formsUl.children('li:visible');
forms.each(function(i) {
$('ul.controls .inline-child-move-up', this).toggleClass('disabled', i == 0).toggleClass('enabled', i != 0);
$('ul.controls .inline-child-move-down', this).toggleClass('disabled', i == forms.length - 1).toggleClass('enabled', i != forms.length - 1);
$('ul.controls .inline-child-move-up', this).toggleClass('disabled', i === 0).toggleClass('enabled', i !== 0);
$('ul.controls .inline-child-move-down', this).toggleClass('disabled', i === forms.length - 1).toggleClass('enabled', i != forms.length - 1);
});
}
}
};
self.animateSwap = function(item1, item2){
var parent = self.formsUl;
@ -187,8 +187,8 @@ function InlinePanel(opts) {
}, 200, function(){
parent.removeClass('moving').removeAttr('style');
children.removeClass('moving').removeAttr('style');
})
}
});
};
buildExpandingFormset(opts.formsetPrefix, {
onAdd: function(formCount) {
@ -228,7 +228,7 @@ function initSlugAutoPopulate(){
function initSlugCleaning(){
$('#id_slug').on('keyup blur', function(){
$(this).val(cleanForSlug($(this).val()));
})
});
}
$(function() {

Wyświetl plik

@ -1,7 +1,9 @@
from taggit.models import Tag
from django.contrib.contenttypes.models import ContentType
from django.db.models import Count, Q
from django.db.models import Count
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailsearch import Indexed, Search
@ -54,7 +56,6 @@ class TagSearchable(Indexed):
# output the list of tags on each result without doing a further query
return [tagged_item.tag for tagged_item in self.tagged_items.all()]
@classmethod
def popular_tags(cls):
content_type = ContentType.objects.get_for_model(cls)

Wyświetl plik

@ -1,14 +1,15 @@
from celery.decorators import task
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.conf import settings
from celery.decorators import task
from wagtail.wagtailcore.models import PageRevision
from django.contrib.auth.models import Permission
from django.contrib.auth import get_user_model
from django.db.models import Q
from wagtail.wagtailcore.models import PageRevision
def users_with_permission(permission, include_superusers=True):
# Get user model
User = get_user_model()
@ -36,13 +37,13 @@ def send_notification(page_revision_id, notification, excluded_user_id):
recipients = users_with_permission('wagtailcore.publish_page')
elif notification == 'approved' or notification == 'rejected':
# Get submitter
recipients = [revision.user]
recipients = [revision.user]
else:
return
# Get list of email addresses
email_addresses = [
recipient.email for recipient in recipients
recipient.email for recipient in recipients
if recipient.email and recipient.id != excluded_user_id
]
@ -65,4 +66,4 @@ def send_notification(page_revision_id, notification, excluded_user_id):
from_email = 'webmaster@localhost'
# Send email
send_mail(email_subject, email_content, from_email, email_addresses)
send_mail(email_subject, email_content, from_email, email_addresses)

Wyświetl plik

@ -2,7 +2,6 @@
{% load wagtailadmin_nav %}
{% block furniture %}
<div id="nav-toggle" data-afteropen="Collapse" class="icon text-replace">Menu</div>
<div class="nav-wrapper">
<div class="inner">
<a href="{% url 'wagtailadmin_home' %}" class="logo"><img src="{{ STATIC_URL }}wagtailadmin/images/wagtail-logo.svg" alt="Wagtail" width="80" /><span>Dashboard</span></a>
@ -17,6 +16,7 @@
</div>
<div class="content-wrapper">
<div id="nav-toggle" data-afteropen="Collapse" class="icon text-replace">Menu</div>
<div class="content">
{# Always show messages div so it can be appended to by JS #}
<div class="messages">

Wyświetl plik

@ -10,7 +10,7 @@
{% endblock %}
{% block furniture %}
<form action="{% url 'django.contrib.auth.views.login' %}" method="post">
<form action="{% url 'django.contrib.auth.views.login' %}" method="post" autocomplete="off">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<h1>Sign in to Wagtail</h1>
@ -52,4 +52,12 @@
</li>
</ul>
</form>
{% endblock %}
{% block extra_js %}
<script>
$(function(){
$('form input[name=username]').focus();
})
</script>
{% endblock %}

Wyświetl plik

@ -2,11 +2,12 @@ from django import template
register = template.Library()
@register.filter("ellipsistrim")
def ellipsistrim(value, max_length):
if len(value) > max_length:
truncd_val = value[:max_length]
if not len(value) == max_length+1 and value[max_length+1] != " ":
truncd_val = truncd_val[:truncd_val.rfind(" ")]
return truncd_val + "..."
return value
return truncd_val + "..."
return value

Wyświetl plik

@ -4,10 +4,10 @@ from wagtail.wagtailcore.util import camelcase_to_underscore
register = template.Library()
@register.filter
def fieldtype(bound_field):
try:
return camelcase_to_underscore(bound_field.field.__class__.__name__)
except AttributeError:
return ""
try:
return camelcase_to_underscore(bound_field.field.__class__.__name__)
except AttributeError:
return ""

Wyświetl plik

@ -8,32 +8,36 @@
### <img src="{% gravatar_url sometemplatevariable %}">
### just make sure to update the "default" image path below
import urllib
import hashlib
from django import template
import urllib, hashlib
register = template.Library()
class GravatarUrlNode(template.Node):
def __init__(self, email, size=50):
self.email = template.Variable(email)
self.size = size
def render(self, context):
try:
email = self.email.resolve(context)
except template.VariableDoesNotExist:
return ''
default = "blank"
size = self.size
gravatar_url = "//www.gravatar.com/avatar/" + hashlib.md5(email.lower()).hexdigest() + "?"
gravatar_url += urllib.urlencode({'s':str(size), 'd':default})
gravatar_url += urllib.urlencode({'s': str(size), 'd': default})
return gravatar_url
@register.tag
def gravatar_url(parser, token):
bits = token.split_contents()
return GravatarUrlNode(*bits[1:])
return GravatarUrlNode(*bits[1:])

Wyświetl plik

@ -1,13 +1,11 @@
from django import template
from wagtail.wagtailcore.util import camelcase_to_underscore
register = template.Library()
@register.filter
def meta_description(model):
try:
return model.model_class()._meta.description
except:
return ""
try:
return model.model_class()._meta.description
except:
return ""

Wyświetl plik

@ -1,8 +1,10 @@
from django import template
from wagtail.wagtailcore.models import UserPagePermissionsProxy
register = template.Library()
@register.assignment_tag(takes_context=True)
def page_permissions(context, page):
"""

Wyświetl plik

@ -1,10 +1,11 @@
from django import template
from django.core import urlresolvers
from wagtail.wagtailcore.models import get_navigation_menu_items
from wagtail.wagtailadmin import hooks
from wagtail.wagtailadmin.menu import MenuItem
from wagtail.wagtailcore.models import get_navigation_menu_items
from wagtail.wagtailsnippets.permissions import user_can_edit_snippets # TODO: reorganise into pluggable architecture so that wagtailsnippets registers its own menu item
register = template.Library()

Wyświetl plik

@ -2,6 +2,7 @@ from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def wagtailuserbar(context, cssfile=""):
try:

Wyświetl plik

@ -1,24 +1,32 @@
from django.conf.urls import patterns, url
from django.conf import settings
from wagtail.wagtailadmin.forms import LoginForm, PasswordResetForm
urlpatterns = patterns('django.contrib.auth.views',
url(r'^login/$', 'login', {
'template_name': 'wagtailadmin/login.html',
'authentication_form': LoginForm,
'extra_context': {'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True)},
}),
urlpatterns = patterns(
'django.contrib.auth.views',
url(
r'^login/$', 'login', {
'template_name': 'wagtailadmin/login.html',
'authentication_form': LoginForm,
'extra_context': {'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True)},
}
),
url(r'^logout/$', 'logout', {'next_page': '/admin/login/'}),
# Password reset
url(r'^password_reset/$', 'password_reset', {
'template_name': 'wagtailadmin/account/password_reset/form.html',
'email_template_name': 'wagtailadmin/account/password_reset/email.txt',
'subject_template_name': 'wagtailadmin/account/password_reset/email_subject.txt',
'password_reset_form': PasswordResetForm,
}, name='password_reset'),
url(
r'^password_reset/$', 'password_reset', {
'template_name': 'wagtailadmin/account/password_reset/form.html',
'email_template_name': 'wagtailadmin/account/password_reset/email.txt',
'subject_template_name': 'wagtailadmin/account/password_reset/email_subject.txt',
'password_reset_form': PasswordResetForm,
}, name='password_reset'
),
url(r'^password_reset/done/$', 'password_reset_done', {'template_name': 'wagtailadmin/account/password_reset/done.html'}, name='password_reset_done'),
url(r'^password_reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
url(
r'^password_reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'password_reset_confirm',
{'template_name': 'wagtailadmin/account/password_reset/confirm.html'},
name='password_reset_confirm',
@ -26,7 +34,8 @@ urlpatterns = patterns('django.contrib.auth.views',
url(r'^password_reset/complete/$', 'password_reset_complete', {'template_name': 'wagtailadmin/account/password_reset/complete.html'}, name='password_reset_complete'),
)
urlpatterns += patterns('wagtail.wagtailadmin.views',
urlpatterns += patterns(
'wagtail.wagtailadmin.views',
url(r'^$', 'home.home', name='wagtailadmin_home'),
url(r'^failwhale/$', 'home.error_test', name='wagtailadmin_error_test'),
@ -50,7 +59,7 @@ urlpatterns += patterns('wagtail.wagtailadmin.views',
url(r'^pages/(\d+)/delete/$', 'pages.delete', name='wagtailadmin_pages_delete'),
url(r'^pages/(\d+)/unpublish/$', 'pages.unpublish', name='wagtailadmin_pages_unpublish'),
url(r'^pages/search/$', 'pages.search', name='wagtailadmin_pages_search'),
url(r'^pages/search/$', 'pages.search', name='wagtailadmin_pages_search'),
url(r'^pages/(\d+)/move/$', 'pages.move_choose_destination', name='wagtailadmin_pages_move'),
url(r'^pages/(\d+)/move/(\d+)/$', 'pages.move_choose_destination', name='wagtailadmin_pages_move_choose_destination'),

Wyświetl plik

@ -30,4 +30,4 @@ def change_password(request):
return render(request, 'wagtailadmin/account/change_password.html', {
'form': form,
'can_change_password': can_change_password,
})
})

Wyświetl plik

@ -4,10 +4,12 @@ from django.http import Http404
from django.utils.http import urlencode
from django.contrib.auth.decorators import login_required
from wagtail.wagtailcore.models import Page
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailadmin.forms import SearchForm, ExternalLinkChooserForm, ExternalLinkChooserWithLinkTextForm, EmailLinkChooserForm, EmailLinkChooserWithLinkTextForm
from wagtail.wagtailcore.models import Page
def get_querystring(request):
return urlencode({
'page_type': request.GET.get('page_type', ''),
@ -16,12 +18,12 @@ def get_querystring(request):
'prompt_for_link_text': request.GET.get('prompt_for_link_text', ''),
})
@login_required
def browse(request, parent_page_id=None):
page_type = request.GET.get('page_type') or 'wagtailcore.page'
content_type_app_name, content_type_model_name = page_type.split('.')
q = None
is_searching = False
try:
@ -34,10 +36,10 @@ def browse(request, parent_page_id=None):
search_form = SearchForm(request.GET)
if search_form.is_valid() and search_form.cleaned_data['q']:
pages = desired_class.objects.exclude(
depth=1 # never include root
depth=1 # never include root
).filter(title__icontains=search_form.cleaned_data['q'])[:10]
is_searching = True
if not is_searching:
if parent_page_id:
parent_page = get_object_or_404(Page, id=parent_page_id)
@ -68,8 +70,7 @@ def browse(request, parent_page_id=None):
'is_searching': is_searching
})
return render_modal_workflow(request, 'wagtailadmin/chooser/browse.html', 'wagtailadmin/chooser/browse.js',{
return render_modal_workflow(request, 'wagtailadmin/chooser/browse.html', 'wagtailadmin/chooser/browse.js', {
'allow_external_link': request.GET.get('allow_external_link'),
'allow_email_link': request.GET.get('allow_email_link'),
'querystring': get_querystring(request),
@ -79,6 +80,7 @@ def browse(request, parent_page_id=None):
'is_searching': False
})
@login_required
def external_link(request):
prompt_for_link_text = bool(request.GET.get('prompt_for_link_text'))
@ -91,7 +93,8 @@ def external_link(request):
if request.POST:
form = form_class(request.POST)
if form.is_valid():
return render_modal_workflow(request,
return render_modal_workflow(
request,
None, 'wagtailadmin/chooser/external_link_chosen.js',
{
'url': form.cleaned_data['url'],
@ -101,7 +104,8 @@ def external_link(request):
else:
form = form_class()
return render_modal_workflow(request,
return render_modal_workflow(
request,
'wagtailadmin/chooser/external_link.html', 'wagtailadmin/chooser/external_link.js',
{
'querystring': get_querystring(request),
@ -110,6 +114,7 @@ def external_link(request):
}
)
@login_required
def email_link(request):
prompt_for_link_text = bool(request.GET.get('prompt_for_link_text'))
@ -122,7 +127,8 @@ def email_link(request):
if request.POST:
form = form_class(request.POST)
if form.is_valid():
return render_modal_workflow(request,
return render_modal_workflow(
request,
None, 'wagtailadmin/chooser/external_link_chosen.js',
{
'url': 'mailto:' + form.cleaned_data['email_address'],
@ -132,7 +138,8 @@ def email_link(request):
else:
form = form_class()
return render_modal_workflow(request,
return render_modal_workflow(
request,
'wagtailadmin/chooser/email_link.html', 'wagtailadmin/chooser/email_link.js',
{
'querystring': get_querystring(request),

Wyświetl plik

@ -4,11 +4,15 @@ from django.conf import settings
from django.template import RequestContext
from django.template.loader import render_to_string
from wagtail.wagtailcore.models import Page, PageRevision, UserPagePermissionsProxy
from wagtail.wagtailimages.models import get_image_model
from wagtail.wagtaildocs.models import Document
from wagtail.wagtailadmin import hooks
from wagtail.wagtailcore.models import Page, PageRevision, UserPagePermissionsProxy
from wagtail.wagtaildocs.models import Document
from wagtail.wagtailimages.models import get_image_model
# Panels for the homepage
class SiteSummaryPanel(object):
name = 'site_summary'
@ -24,6 +28,7 @@ class SiteSummaryPanel(object):
'total_docs': Document.objects.count(),
}, RequestContext(self.request))
class PagesForModerationPanel(object):
name = 'pages_for_moderation'
order = 200
@ -38,6 +43,7 @@ class PagesForModerationPanel(object):
'page_revisions_for_moderation': self.page_revisions_for_moderation,
}, RequestContext(self.request))
class RecentEditsPanel(object):
name = 'recent_edits'
order = 300
@ -52,6 +58,7 @@ class RecentEditsPanel(object):
'last_edits': self.last_edits,
}, RequestContext(self.request))
@login_required
def home(request):
@ -67,7 +74,7 @@ def home(request):
return render(request, "wagtailadmin/home.html", {
'site_name': settings.WAGTAIL_SITE_NAME,
'panels': sorted(panels, key=lambda p: p.order),
'user':request.user
'user': request.user
})

Wyświetl plik

@ -3,17 +3,17 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import ValidationError, PermissionDenied
from django.template.loader import render_to_string
from django.template import RequestContext
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailcore.models import Page, PageRevision, get_page_types
from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
from wagtail.wagtailadmin.forms import SearchForm
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailadmin import tasks, hooks
from wagtail.wagtailcore.models import Page, PageRevision, get_page_types
@login_required
def index(request, parent_page_id=None):
@ -32,9 +32,6 @@ def index(request, parent_page_id=None):
pages = pages.order_by(ordering)
else:
ordering = 'title'
# if ordering == 'ord':
# messages.warning(request, "You are now able to reorder pages. Click 'Save order' when you've finished")
return render(request, 'wagtailadmin/pages/index.html', {
'parent_page': parent_page,
@ -61,7 +58,7 @@ def select_type(request):
return render(request, 'wagtailadmin/pages/select_type.html', {
'page_types': page_types,
'all_page_types':all_page_types
'all_page_types': all_page_types
})
@ -80,6 +77,7 @@ def add_subpage(request, parent_page_id):
'all_page_types': all_page_types,
})
@login_required
def select_location(request, content_type_app_name, content_type_model_name):
try:
@ -111,6 +109,7 @@ def select_location(request, content_type_app_name, content_type_model_name):
'parent_pages': parent_pages,
})
@login_required
def content_type_use(request, content_type_app_name, content_type_model_name):
try:
@ -275,7 +274,6 @@ def edit(request, page_id):
form = form_class(instance=page)
edit_handler = edit_handler_class(instance=page, form=form)
# Check for revisions still undergoing moderation and warn
if latest_revision and latest_revision.submitted_for_moderation:
messages.warning(request, "This page is currently awaiting moderation")
@ -286,6 +284,7 @@ def edit(request, page_id):
'errors_debug': errors_debug,
})
@login_required
def delete(request, page_id):
page = get_object_or_404(Page, id=page_id)
@ -309,11 +308,13 @@ def delete(request, page_id):
'descendant_count': page.get_descendant_count()
})
@login_required
def view_draft(request, page_id):
page = get_object_or_404(Page, id=page_id).get_latest_revision_as_page()
return page.serve(request)
@login_required
def preview_on_edit(request, page_id):
# Receive the form submission that would typically be posted to the 'edit' view. If submission is valid,
@ -347,6 +348,7 @@ def preview_on_edit(request, page_id):
response['X-Wagtail-Preview'] = 'error'
return response
@login_required
def preview_on_create(request, content_type_app_name, content_type_model_name, parent_page_id):
# Receive the form submission that would typically be posted to the 'create' view. If submission is valid,
@ -387,6 +389,7 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p
response['X-Wagtail-Preview'] = 'error'
return response
def preview_placeholder(request):
"""
The HTML of a previewed page is written to the destination browser window using document.write.
@ -410,6 +413,7 @@ def preview_placeholder(request):
"""
return render(request, 'wagtailadmin/pages/preview_placeholder.html')
@login_required
def unpublish(request, page_id):
page = get_object_or_404(Page, id=page_id)
@ -427,6 +431,7 @@ def unpublish(request, page_id):
'page': page,
})
@login_required
def move_choose_destination(request, page_to_move_id, viewed_page_id=None):
page_to_move = get_object_or_404(Page, id=page_to_move_id)
@ -456,6 +461,7 @@ def move_choose_destination(request, page_to_move_id, viewed_page_id=None):
'child_pages': child_pages,
})
@login_required
def move_confirm(request, page_to_move_id, destination_id):
page_to_move = get_object_or_404(Page, id=page_to_move_id)
@ -477,6 +483,7 @@ def move_confirm(request, page_to_move_id, destination_id):
'destination': destination,
})
@login_required
def set_page_position(request, page_to_move_id):
page_to_move = get_object_or_404(Page, id=page_to_move_id)
@ -495,7 +502,7 @@ def set_page_position(request, page_to_move_id):
try:
position_page = parent_page.get_children()[int(position)]
except IndexError:
pass # No page in this position
pass # No page in this position
# Move page
@ -511,7 +518,10 @@ def set_page_position(request, page_to_move_id):
return HttpResponse('')
PAGE_EDIT_HANDLERS = {}
def get_page_edit_handler(page_class):
if page_class not in PAGE_EDIT_HANDLERS:
PAGE_EDIT_HANDLERS[page_class] = TabbedInterface([
@ -540,11 +550,11 @@ def search(request):
# Pagination
paginator = Paginator(pages, 20)
try:
pages = paginator.page(p)
pages = paginator.page(p)
except PageNotAnInteger:
pages = paginator.page(1)
pages = paginator.page(1)
except EmptyPage:
pages = paginator.page(paginator.num_pages)
pages = paginator.page(paginator.num_pages)
else:
form = SearchForm()
@ -580,6 +590,7 @@ def approve_moderation(request, revision_id):
return redirect('wagtailadmin_home')
@login_required
def reject_moderation(request, revision_id):
revision = get_object_or_404(PageRevision, id=revision_id)
@ -598,6 +609,7 @@ def reject_moderation(request, revision_id):
return redirect('wagtailadmin_home')
@login_required
def preview_for_moderation(request, revision_id):
revision = get_object_or_404(PageRevision, id=revision_id)

Wyświetl plik

@ -1,7 +1,10 @@
import json
from taggit.models import Tag
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from taggit.models import Tag
import json
@login_required
def autocomplete(request):

Wyświetl plik

@ -1,5 +1,4 @@
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import GroupAdmin
@ -8,6 +7,7 @@ from wagtail.wagtailcore.models import Site, Page, GroupPagePermission
admin.site.register(Site)
admin.site.register(Page)
# Extend GroupAdmin to include page permissions as an inline
class GroupPagePermissionInline(admin.TabularInline):
model = GroupPagePermission
@ -15,6 +15,7 @@ class GroupPagePermissionInline(admin.TabularInline):
verbose_name = 'page permission'
verbose_name_plural = 'page permissions'
class GroupAdminWithPagePermissions(GroupAdmin):
inlines = GroupAdmin.inlines + [GroupPagePermissionInline]

Wyświetl plik

@ -4,6 +4,7 @@ from south.modelsinspector import add_introspection_rules
from wagtail.wagtailcore.rich_text import DbWhitelister, expand_db_html
class RichTextArea(Textarea):
def get_panel(self):
from wagtail.wagtailadmin.edit_handlers import RichTextFieldPanel

Wyświetl plik

@ -3,6 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist
from wagtail.wagtailcore.models import Page
class Command(NoArgsCommand):
def handle_noargs(self, **options):
problems_found = False

Wyświetl plik

@ -1,4 +1,5 @@
from django.core.management.base import BaseCommand
from wagtail.wagtailcore.models import Page
@ -18,4 +19,4 @@ class Command(BaseCommand):
for page in pages:
page.move(to_page, pos='last-child')
print 'Done'
print 'Done'

Wyświetl plik

@ -1,5 +1,6 @@
from django.core.management.base import BaseCommand
from django.db import models
from wagtail.wagtailcore.models import PageRevision, get_page_types
@ -15,6 +16,7 @@ def replace_in_model(model, from_text, to_text):
if updated_fields:
model.save(update_fields=updated_fields)
class Command(BaseCommand):
def handle(self, from_text, to_text, **options):
for revision in PageRevision.objects.filter(content_json__contains=from_text):

Wyświetl plik

@ -2,6 +2,7 @@ from django.core.management.base import NoArgsCommand
from wagtail.wagtailcore.models import Page
class Command(NoArgsCommand):
def set_subtree(self, root, root_path):
root.url_path = root_path

Wyświetl plik

@ -1,5 +1,6 @@
from wagtail.wagtailcore.models import Site
class SiteMiddleware(object):
def process_request(self, request):
"""

Wyświetl plik

@ -1,17 +1,18 @@
from modelcluster.models import ClusterableModel
from treebeard.mp_tree import MP_Node
from django.db import models, connection, transaction
from django.db.models import get_model, Q
from django.http import Http404
from django.shortcuts import render
from django.core.cache import cache
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Group
from treebeard.mp_tree import MP_Node
from modelcluster.models import ClusterableModel
from wagtail.wagtailsearch import Indexed, Searcher
from wagtail.wagtailcore.util import camelcase_to_underscore
from wagtail.wagtailsearch import Indexed, Searcher
class SiteManager(models.Manager):
def get_by_natural_key(self, hostname):
@ -76,6 +77,8 @@ class Site(models.Model):
PAGE_MODEL_CLASSES = []
_PAGE_CONTENT_TYPES = []
def get_page_types():
global _PAGE_CONTENT_TYPES
if len(_PAGE_CONTENT_TYPES) != len(PAGE_MODEL_CLASSES):
@ -84,8 +87,11 @@ def get_page_types():
]
return _PAGE_CONTENT_TYPES
LEAF_PAGE_MODEL_CLASSES = []
_LEAF_PAGE_CONTENT_TYPE_IDS = []
def get_leaf_page_content_type_ids():
global _LEAF_PAGE_CONTENT_TYPE_IDS
if len(_LEAF_PAGE_CONTENT_TYPE_IDS) != len(LEAF_PAGE_MODEL_CLASSES):
@ -94,8 +100,11 @@ def get_leaf_page_content_type_ids():
]
return _LEAF_PAGE_CONTENT_TYPE_IDS
NAVIGABLE_PAGE_MODEL_CLASSES = []
_NAVIGABLE_PAGE_CONTENT_TYPE_IDS = []
def get_navigable_page_content_type_ids():
global _NAVIGABLE_PAGE_CONTENT_TYPE_IDS
if len(_NAVIGABLE_PAGE_CONTENT_TYPE_IDS) != len(NAVIGABLE_PAGE_MODEL_CLASSES):
@ -104,6 +113,7 @@ def get_navigable_page_content_type_ids():
]
return _NAVIGABLE_PAGE_CONTENT_TYPE_IDS
class PageBase(models.base.ModelBase):
"""Metaclass for Page"""
def __init__(cls, name, bases, dct):
@ -137,7 +147,7 @@ class Page(MP_Node, ClusterableModel, Indexed):
__metaclass__ = PageBase
title = models.CharField(max_length=255, help_text="The page title as you'd like it to be seen by the public")
slug = models.SlugField()
slug = models.SlugField(help_text="The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/")
# TODO: enforce uniqueness on slug field per parent (will have to be done at the Django
# level rather than db, since there is no explicit parent relation in the db)
content_type = models.ForeignKey('contenttypes.ContentType', related_name='pages')
@ -420,6 +430,7 @@ class Page(MP_Node, ClusterableModel, Indexed):
user_perms = UserPagePermissionsProxy(user)
return user_perms.for_page(self)
def get_navigation_menu_items():
# Get all pages that appear in the navigation menu: ones which have children,
# or are a non-leaf type (indicating that they *could* have children),
@ -487,6 +498,7 @@ class SubmittedRevisionsManager(models.Manager):
def get_query_set(self):
return super(SubmittedRevisionsManager, self).get_query_set().filter(submitted_for_moderation=True)
class PageRevision(models.Model):
page = models.ForeignKey('Page', related_name='revisions')
submitted_for_moderation = models.BooleanField(default=False)
@ -537,6 +549,7 @@ PAGE_PERMISSION_TYPE_CHOICES = [
('publish', 'Publish'),
]
class GroupPagePermission(models.Model):
group = models.ForeignKey(Group, related_name='page_permissions')
page = models.ForeignKey('Page', related_name='group_permissions')
@ -580,6 +593,7 @@ class UserPagePermissionsProxy(object):
permission to perform specific tasks on the given page"""
return PagePermissionTester(self, page)
class PagePermissionTester(object):
def __init__(self, user_perms, page):
self.user = user_perms.user

Wyświetl plik

@ -1,17 +1,18 @@
from django.utils.html import escape
import re # parsing HTML with regexes LIKE A BOSS.
from django.utils.html import escape
from wagtail.wagtailcore.whitelist import Whitelister
from wagtail.wagtailcore.models import Page
from wagtail.wagtaildocs.models import Document
# FIXME: we don't really want to import wagtailimages within core.
# For that matter, we probably don't want core to be concerned about translating
# HTML for the benefit of the hallo.js editor...
from wagtail.wagtailimages.models import get_image_model
from wagtail.wagtailimages.formats import get_image_format
from wagtail.wagtaildocs.models import Document
# Define a set of 'embed handlers' and 'link handlers'. These handle the translation
# of 'special' HTML elements in rich text - ones which we do not want to include
@ -187,6 +188,7 @@ FIND_A_TAG = re.compile(r'<a(\b[^>]*)>')
FIND_EMBED_TAG = re.compile(r'<embed(\b[^>]*)/>')
FIND_ATTRS = re.compile(r'([\w-]+)\="([^"]*)"')
def extract_attrs(attr_string):
"""
helper method to extract tag attributes as a dict. Does not escape HTML entities!
@ -196,6 +198,7 @@ def extract_attrs(attr_string):
attributes[name] = val
return attributes
def expand_db_html(html, for_editor=False):
"""
Expand database-representation HTML into proper HTML usable in either

Wyświetl plik

@ -2,6 +2,7 @@ from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def pageurl(context, page):
"""

Wyświetl plik

@ -5,6 +5,7 @@ from wagtail.wagtailcore.rich_text import expand_db_html
register = template.Library()
@register.filter
def richtext(value):
return mark_safe(expand_db_html(value))

Wyświetl plik

@ -1,10 +1,11 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailcore.views',
urlpatterns = patterns(
'wagtail.wagtailcore.views',
# All front-end views are handled through Wagtail's core.views.serve mechanism.
# Here we match a (possibly empty) list of path segments, each followed by
# a '/'. If a trailing slash is not present, we leave CommonMiddleware to
# handle it as usual (i.e. redirect it to the trailing slash version if
# settings.APPEND_SLASH is True)
url(r'^((?:[\w\-]+/)*)$', 'serve' )
url(r'^((?:[\w\-]+/)*)$', 'serve')
)

Wyświetl plik

@ -1,5 +1,6 @@
import re
def camelcase_to_underscore(str):
# http://djangosnippets.org/snippets/585/
return re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', str).lower().strip('_')

Wyświetl plik

@ -8,6 +8,7 @@ from urlparse import urlparse
ALLOWED_URL_SCHEMES = ['', 'http', 'https', 'ftp', 'mailto', 'tel']
def check_url(url_string):
# TODO: more paranoid checks (urlparse doesn't catch "jav\tascript:alert('XSS')")
url = urlparse(url_string)
@ -46,6 +47,7 @@ def attribute_rule(allowed_attrs):
allow_without_attributes = attribute_rule({})
class Whitelister(object):
element_rules = {
'[document]': allow_without_attributes,

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtaildocs.views',
urlpatterns = patterns(
'wagtail.wagtaildocs.views',
url(r'^$', 'documents.index', name='wagtaildocs_index'),
url(r'^add/$', 'documents.add', name='wagtaildocs_add_document'),
url(r'^edit/(\d+)/$', 'documents.edit', name='wagtaildocs_edit_document'),

Wyświetl plik

@ -1,10 +1,12 @@
from wagtail.wagtailadmin.edit_handlers import BaseChooserPanel
class BaseDocumentChooserPanel(BaseChooserPanel):
field_template = "wagtaildocs/edit_handlers/document_chooser_panel.html"
object_type_name = "document"
js_function_name = "createDocumentChooser"
def DocumentChooserPanel(field_name):
return type('_DocumentChooserPanel', (BaseDocumentChooserPanel,), {
'field_name': field_name,

Wyświetl plik

@ -1,12 +1,12 @@
import os.path
from taggit.managers import TaggableManager
from django.db import models
from django.db.models.signals import pre_delete
from django.dispatch.dispatcher import receiver
from django.core.urlresolvers import reverse
import os.path
from taggit.managers import TaggableManager
from wagtail.wagtailadmin.taggable import TagSearchable
@ -48,6 +48,7 @@ class Document(models.Model, TagSearchable):
else:
return False
# Receive the pre_delete signal and delete the file associated with the model instance.
@receiver(pre_delete, sender=Document)
def image_delete(sender, instance, **kwargs):

Wyświetl plik

@ -1,5 +1,6 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtaildocs.views',
urlpatterns = patterns(
'wagtail.wagtaildocs.views',
url(r'^(\d+)/(.*)$', 'serve.serve', name='wagtaildocs_serve'),
)

Wyświetl plik

@ -1,13 +1,14 @@
import json
from django.shortcuts import get_object_or_404, render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required, permission_required
import json
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtaildocs.models import Document
from wagtail.wagtaildocs.forms import DocumentForm
from wagtail.wagtailadmin.forms import SearchForm
@login_required
@ -18,7 +19,7 @@ def chooser(request):
uploadform = None
documents = []
q = None
is_searching = False
if 'q' in request.GET or 'p' in request.GET:
@ -30,12 +31,12 @@ def chooser(request):
p = request.GET.get("p", 1)
documents = Document.search(q, results_per_page=10, prefetch_tags=True)
is_searching = True
else:
documents = Document.objects.order_by('-created_at')
p = request.GET.get("p", 1)
paginator = Paginator(documents, 10)
@ -45,7 +46,7 @@ def chooser(request):
documents = paginator.page(1)
except EmptyPage:
documents = paginator.page(paginator.num_pages)
is_searching = False
return render(request, "wagtaildocs/chooser/results.html", {
@ -68,8 +69,8 @@ def chooser(request):
documents = paginator.page(paginator.num_pages)
return render_modal_workflow(request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', {
'documents': documents,
'uploadform': uploadform,
'documents': documents,
'uploadform': uploadform,
'searchform': searchform,
'is_searching': False,
})

Wyświetl plik

@ -4,9 +4,10 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import PermissionDenied
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtaildocs.models import Document
from wagtail.wagtaildocs.forms import DocumentForm
from wagtail.wagtailadmin.forms import SearchForm
@permission_required('wagtaildocs.add_document')
@ -15,7 +16,7 @@ def index(request):
q = None
p = request.GET.get("p", 1)
is_searching = False
if 'q' in request.GET:
form = SearchForm(request.GET, placeholder_suffix="documents")
if form.is_valid():
@ -39,13 +40,12 @@ def index(request):
documents = documents.filter(uploaded_by_user=request.user)
form = SearchForm(placeholder_suffix="documents")
if 'ordering' in request.GET:
ordering = request.GET['ordering']
ordering = request.GET['ordering']
if ordering in ['title', '-created_at']:
if ordering != '-created_at':
documents = documents.order_by(ordering)
documents = documents.order_by(ordering)
else:
ordering = '-created_at'
@ -61,14 +61,14 @@ def index(request):
if request.is_ajax():
return render(request, "wagtaildocs/documents/results.html", {
'ordering':ordering,
'ordering': ordering,
'documents': documents,
'is_searching': is_searching,
'search_query': q,
})
else:
return render(request, "wagtaildocs/documents/index.html", {
'ordering':ordering,
'ordering': ordering,
'search_form': form,
'documents': documents,
'popular_tags': Document.popular_tags(),

Wyświetl plik

@ -4,6 +4,7 @@ from django.http import HttpResponse
from wagtail.wagtaildocs.models import Document
def serve(request, document_id, document_filename):
doc = get_object_or_404(Document, id=document_id)
wrapper = FileWrapper(doc.file)

Wyświetl plik

@ -1,6 +1,8 @@
from datetime import datetime
from django.conf import settings
from embedly import Embedly
from django.conf import settings
from .models import Embed
@ -23,8 +25,17 @@ def get_embed(url, max_width=None):
return None
# Save result to database
row, created = Embed.objects.get_or_create(url=url, max_width=max_width,
defaults={'type': oembed.type, 'title': oembed.title, 'thumbnail_url': oembed.thumbnail_url, 'width': oembed.width, 'height': oembed.height})
row, created = Embed.objects.get_or_create(
url=url,
max_width=max_width,
defaults={
'type': oembed.type,
'title': oembed.title,
'thumbnail_url': oembed.thumbnail_url,
'width': oembed.width,
'height': oembed.height
}
)
if oembed.type == 'photo':
html = '<img src="%s" />' % (oembed.url, )
@ -37,4 +48,4 @@ def get_embed(url, max_width=None):
row.save()
# Return new embed
return row
return row

Wyświetl plik

@ -1,7 +1,9 @@
from __future__ import division # Use true division
from .embeds import get_embed
from __future__ import division # Use true division
from django.utils.html import escape
from .embeds import get_embed
def embed_to_frontend_html(url):
embed = get_embed(url)
@ -23,4 +25,4 @@ def embed_to_editor_html(url):
embed = get_embed(url)
if embed is None:
return ''
return '<div class="embed-placeholder" contenteditable="false" data-embedtype="media" data-url="%s"><h3>%s</h3><p>%s</p><img src="%s"></div>' % (url, escape(embed.title), url, embed.thumbnail_url)
return '<div class="embed-placeholder" contenteditable="false" data-embedtype="media" data-url="%s"><h3>%s</h3><p>%s</p><img src="%s"></div>' % (url, escape(embed.title), url, embed.thumbnail_url)

Wyświetl plik

@ -12,4 +12,4 @@ def validate_url(url):
class EmbedForm(forms.Form):
url = forms.CharField(label="URL", validators=[validate_url])
url = forms.CharField(label="URL", validators=[validate_url])

Wyświetl plik

@ -24,4 +24,4 @@ class Embed(models.Model):
unique_together = ('url', 'max_width')
def __unicode__(self):
return self.url
return self.url

Wyświetl plik

@ -1,6 +1,6 @@
import re
from django import template
from django.utils.safestring import mark_safe
from wagtail.wagtailembeds.embeds import get_embed

Wyświetl plik

@ -1,9 +1,10 @@
from .embeds import get_embed
from django.test import TestCase
from .embeds import get_embed
class TestEmbeds(TestCase):
def test_get_embed(self):
# This test will fail if the video is removed or the title is changed
embed = get_embed('http://www.youtube.com/watch?v=S3xAeTmsJfg')
self.assertEqual(embed.title, 'Animation: Ferret dance (A series of tubes)')
self.assertEqual(embed.title, 'Animation: Ferret dance (A series of tubes)')

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailembeds.views',
urlpatterns = patterns(
'wagtail.wagtailembeds.views',
url(r'^chooser/$', 'chooser.chooser', name='wagtailembeds_chooser'),
url(r'^chooser/upload/$', 'chooser.chooser_upload', name='wagtailembeds_chooser_upload'),
)

Wyświetl plik

@ -1,14 +1,16 @@
from django.forms.util import ErrorList
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailembeds.forms import EmbedForm
from wagtail.wagtailembeds.format import embed_to_editor_html
from django.forms.util import ErrorList
def chooser(request):
form = EmbedForm()
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js',{
'form': form,
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js', {
'form': form,
})
@ -26,12 +28,12 @@ def chooser_upload(request):
else:
errors = form._errors.setdefault('url', ErrorList())
errors.append('This URL is not recognised')
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js',{
'form': form,
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js', {
'form': form,
})
else:
form = EmbedForm()
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js',{
'form': form,
})
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js', {
'form': form,
})

Wyświetl plik

@ -3,6 +3,7 @@ from django.conf import settings
from wagtail.wagtailimages.models import Image
if hasattr(settings, 'WAGTAILIMAGES_IMAGE_MODEL') and settings.WAGTAILIMAGES_IMAGE_MODEL != 'wagtailimages.Image':
# This installation provides its own custom image class;
# to avoid confusion, we won't expose the unused wagtailimages.Image class

Wyświetl plik

@ -1,10 +1,12 @@
from wagtail.wagtailadmin.edit_handlers import BaseChooserPanel
class BaseImageChooserPanel(BaseChooserPanel):
field_template = "wagtailimages/edit_handlers/image_chooser_panel.html"
object_type_name = "image"
js_function_name = "createImageChooser"
def ImageChooserPanel(field_name):
return type('_ImageChooserPanel', (BaseImageChooserPanel,), {
'field_name': field_name,

Wyświetl plik

@ -2,6 +2,7 @@ from django.conf import settings
from django.utils.importlib import import_module
from django.utils.html import escape
class Format(object):
def __init__(self, name, label, classnames, filter_spec):
self.name = name
@ -40,12 +41,14 @@ class Format(object):
FORMATS = []
FORMATS_BY_NAME = {}
def register_image_format(format):
if format.name in FORMATS_BY_NAME:
raise KeyError("Image format '%s' is already registered" % format.name)
FORMATS_BY_NAME[format.name] = format
FORMATS.append(format)
def unregister_image_format(format_name):
global FORMATS
# handle being passed a format object rather than a format name string
@ -60,15 +63,20 @@ def unregister_image_format(format_name):
except KeyError:
raise KeyError("Image format '%s' is not registered" % format_name)
def get_image_formats():
search_for_image_formats()
return FORMATS
def get_image_format(name):
search_for_image_formats()
return FORMATS_BY_NAME[name]
_searched_for_image_formats = False
def search_for_image_formats():
global _searched_for_image_formats
if not _searched_for_image_formats:

Wyświetl plik

@ -6,11 +6,12 @@ from wagtail.wagtailimages.formats import get_image_formats
def get_image_form():
return modelform_factory(get_image_model(),
return modelform_factory(
get_image_model(),
# set the 'file' widget to a FileInput rather than the default ClearableFileInput
# so that when editing, we don't get the 'currently: ...' banner which is
# a bit pointless here
widgets = {'file': forms.FileInput()})
widgets={'file': forms.FileInput()})
class ImageInsertionForm(forms.Form):

Wyświetl plik

@ -1,5 +1,6 @@
from PIL import Image
def resize(image, size):
"""
resize image to the requested size, using highest quality settings

Wyświetl plik

@ -1,3 +1,9 @@
import StringIO
import os.path
import PIL.Image
from taggit.managers import TaggableManager
from django.core.files import File
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, ValidationError
from django.db import models
@ -6,12 +12,6 @@ from django.dispatch.dispatcher import receiver
from django.utils.safestring import mark_safe
from django.utils.html import escape
import StringIO
import PIL.Image
import os.path
from taggit.managers import TaggableManager
from wagtail.wagtailadmin.taggable import TagSearchable
from wagtail.wagtailimages import image_ops
@ -24,7 +24,7 @@ class AbstractImage(models.Model, TagSearchable):
filename = self.file.field.storage.get_valid_name(filename)
# replace non-ascii characters in filename with _ , to sidestep issues with filesystem encoding
filename = "".join((i if ord(i)<128 else '_') for i in filename)
filename = "".join((i if ord(i) < 128 else '_') for i in filename)
while len(os.path.join(folder_name, filename)) >= 95:
prefix, dot, extension = filename.rpartition('.')
@ -75,6 +75,7 @@ class AbstractImage(models.Model, TagSearchable):
def is_portrait(self):
return (self.width < self.height)
def is_landscape(self):
return (self.height < self.width)
@ -100,7 +101,8 @@ class AbstractImage(models.Model, TagSearchable):
return False
class Meta:
abstract=True
abstract = True
class Image(AbstractImage):
pass
@ -216,7 +218,7 @@ class AbstractRendition(models.Model):
)
class Meta:
abstract=True
abstract = True
class Rendition(AbstractRendition):
@ -227,6 +229,7 @@ class Rendition(AbstractRendition):
('image', 'filter'),
)
# Receive the pre_delete signal and delete the file associated with the model instance.
@receiver(pre_delete, sender=Rendition)
def rendition_delete(sender, instance, **kwargs):

Wyświetl plik

@ -4,6 +4,7 @@ from wagtail.wagtailimages.models import Filter
register = template.Library()
@register.tag(name="image")
def image(parser, token):
args = token.split_contents()
@ -25,6 +26,7 @@ def image(parser, token):
else:
raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}")
class ImageNode(template.Node):
def __init__(self, image_var_name, filter_spec, output_var_name=None):
self.image_var = template.Variable(image_var_name)

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailimages.views',
urlpatterns = patterns(
'wagtail.wagtailimages.views',
url(r'^$', 'images.index', name='wagtailimages_index'),
url(r'^(\d+)/$', 'images.edit', name='wagtailimages_edit_image'),
url(r'^(\d+)/delete/$', 'images.delete', name='wagtailimages_delete_image'),

Wyświetl plik

@ -1,13 +1,14 @@
import json
from django.shortcuts import get_object_or_404, render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required, permission_required
import json
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailimages.models import get_image_model
from wagtail.wagtailimages.forms import get_image_form, ImageInsertionForm
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailimages.formats import get_image_format
@ -28,6 +29,7 @@ def get_image_json(image):
}
})
@login_required
def chooser(request):
Image = get_image_model()
@ -43,10 +45,10 @@ def chooser(request):
searchform = SearchForm(request.GET)
if searchform.is_valid():
q = searchform.cleaned_data['q']
# page number
p = request.GET.get("p", 1)
images = Image.search(q, results_per_page=10, page=p)
is_searching = True
@ -62,11 +64,11 @@ def chooser(request):
images = paginator.page(1)
except EmptyPage:
images = paginator.page(paginator.num_pages)
is_searching = False
return render(request, "wagtailimages/chooser/results.html", {
'images': images,
'images': images,
'is_searching': is_searching,
'will_select_format': request.GET.get('select_format')
})
@ -83,11 +85,10 @@ def chooser(request):
images = paginator.page(1)
except EmptyPage:
images = paginator.page(paginator.num_pages)
return render_modal_workflow(request, 'wagtailimages/chooser/chooser.html', 'wagtailimages/chooser/chooser.js',{
'images': images,
'uploadform': uploadform,
return render_modal_workflow(request, 'wagtailimages/chooser/chooser.html', 'wagtailimages/chooser/chooser.js', {
'images': images,
'uploadform': uploadform,
'searchform': searchform,
'is_searching': False,
'will_select_format': request.GET.get('select_format'),

Wyświetl plik

@ -4,9 +4,11 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import permission_required, login_required
from django.core.exceptions import PermissionDenied
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailimages.models import get_image_model
from wagtail.wagtailimages.forms import get_image_form
from wagtail.wagtailadmin.forms import SearchForm
@permission_required('wagtailimages.add_image')
def index(request):
@ -144,7 +146,7 @@ def search(request):
images = []
q = None
is_searching = False
if 'q' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():

Wyświetl plik

@ -4,7 +4,7 @@ import models
class RedirectForm(forms.ModelForm):
required_css_class = "required"
class Meta:
model = models.Redirect
required_css_class = "required"
class Meta:
model = models.Redirect

Wyświetl plik

@ -2,6 +2,7 @@ from django import http
import models
# Originally pinched from: https://github.com/django/django/blob/master/django/contrib/redirects/middleware.py
class RedirectMiddleware(object):
def process_response(self, request, response):
@ -23,4 +24,4 @@ class RedirectMiddleware(object):
except:
pass
return response
return response

Wyświetl plik

@ -41,7 +41,6 @@ class Migration(SchemaMigration):
'Meta': {'object_name': 'Page'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': u"orm['contenttypes.ContentType']"}),
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
'feed_image': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': u"orm['rca.RcaImage']"}),
'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
@ -61,24 +60,6 @@ class Migration(SchemaMigration):
'port': ('django.db.models.fields.IntegerField', [], {'default': '80'}),
'root_page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sites_rooted_here'", 'to': u"orm['wagtailcore.Page']"})
},
u'rca.rcaimage': {
'Meta': {'object_name': 'RcaImage'},
'alt': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'creator': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'dimensions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'eprint_docid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'height': ('django.db.models.fields.IntegerField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'medium': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'permission': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'photographer': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'rca_content_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'width': ('django.db.models.fields.IntegerField', [], {}),
'year': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
u'taggit.tag': {
'Meta': {'object_name': 'Tag'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),

Wyświetl plik

@ -1,4 +1,5 @@
from django.db import models
from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, PageChooserPanel
@ -69,4 +70,4 @@ Redirect.content_panels = [
PageChooserPanel('redirect_page'),
FieldPanel('redirect_link'),
])
]
]

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailredirects.views',
urlpatterns = patterns(
'wagtail.wagtailredirects.views',
url(r'^$', 'index', name='wagtailredirects_index'),
url(r'^(\d+)/$', 'edit', name='wagtailredirects_edit_redirect'),
url(r'^(\d+)/delete/$', 'delete', name='wagtailredirects_delete_redirect'),

Wyświetl plik

@ -1,17 +1,17 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import permission_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailadmin.edit_handlers import ObjectList
from wagtail.wagtailadmin.forms import SearchForm
import models
import forms
REDIRECT_EDIT_HANDLER = ObjectList(models.Redirect.content_panels)
@permission_required('wagtailredirects.change_redirect')
def index(request):
p = request.GET.get("p", 1)
@ -25,18 +25,18 @@ def index(request):
is_searching = True
redirects = models.Redirect.get_for_site(site=request.site).prefetch_related('redirect_page').filter(old_path__icontains=q)
if not is_searching:
# Get redirects
redirects = models.Redirect.get_for_site(site=request.site).prefetch_related('redirect_page')
form = SearchForm(placeholder_suffix="redirects")
if 'ordering' in request.GET:
ordering = request.GET['ordering']
ordering = request.GET['ordering']
if ordering in ['old_path',]:
if ordering in ['old_path', ]:
if ordering != 'old_path':
redirects = redirects.order_by(ordering)
redirects = redirects.order_by(ordering)
else:
ordering = 'old_path'
@ -52,7 +52,7 @@ def index(request):
# Render template
if request.is_ajax():
return render(request, "wagtailredirects/results.html", {
'ordering':ordering,
'ordering': ordering,
'redirects': redirects,
'is_searching': is_searching,
'search_query': q,
@ -65,6 +65,7 @@ def index(request):
'is_searching': is_searching,
})
@permission_required('wagtailredirects.change_redirect')
def edit(request, redirect_id):
theredirect = get_object_or_404(models.Redirect, id=redirect_id)
@ -126,4 +127,4 @@ def add(request):
return render(request, "wagtailredirects/add.html", {
'edit_handler': edit_handler,
})
})

Wyświetl plik

@ -1,5 +1,6 @@
from django import forms
from django.forms.models import inlineformset_factory
import models
@ -24,6 +25,7 @@ class EditorsPickForm(forms.ModelForm):
EditorsPickFormSetBase = inlineformset_factory(models.Query, models.EditorsPick, form=EditorsPickForm, can_order=True, can_delete=True, extra=0)
class EditorsPickFormSet(EditorsPickFormSetBase):
def add_fields(self, form, *args, **kwargs):
super(EditorsPickFormSet, self).add_fields(form, *args, **kwargs)
@ -33,4 +35,4 @@ class EditorsPickFormSet(EditorsPickFormSetBase):
form.fields['ORDER'].widget = forms.HiddenInput()
# Remove query field
del form.fields['query']
del form.fields['query']

Wyświetl plik

@ -5,7 +5,7 @@ class Indexed(object):
@classmethod
def indexed_get_parent(cls, require_model=True):
for base in cls.__bases__:
if issubclass(base, Indexed) and (issubclass(base, models.Model) or require_model == False):
if issubclass(base, Indexed) and (issubclass(base, models.Model) or require_model is False):
return base
@classmethod
@ -29,7 +29,7 @@ class Indexed(object):
return parent.indexed_get_content_type()
else:
# At toplevel, return this content type
return (cls._meta.app_label + "_" + cls.__name__).lower()
return (cls._meta.app_label + "_" + cls.__name__).lower()
@classmethod
def indexed_get_indexed_fields(cls):
@ -75,4 +75,4 @@ class Indexed(object):
return doc
indexed_fields = ()
indexed = True
indexed = True

Wyświetl plik

@ -1,4 +1,5 @@
from django.core.management.base import NoArgsCommand
from wagtail.wagtailsearch import models
@ -12,4 +13,4 @@ class Command(NoArgsCommand):
# Clean queries
print "Cleaning query records... ",
models.Query.garbage_collect()
print "Done"
print "Done"

Wyświetl plik

@ -1,6 +1,6 @@
from django.core.management.base import NoArgsCommand
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from wagtail.wagtailsearch.indexed import Indexed
from wagtail.wagtailsearch.search import Search
@ -18,8 +18,8 @@ class Command(NoArgsCommand):
# Add all objects to object set and detect any duplicates
# Duplicates are caused when both a model and a derived model are indexed
# Eg, StudentPage inherits from Page and both of these models are indexed
# If we were to add all objects from both models into the index, all the StudentPages will have two entries
# Eg, if BlogPost inherits from Page and both of these models are indexed
# If we were to add all objects from both models into the index, all the BlogPosts will have two entries
for model in indexed_models:
# Get toplevel content type
toplevel_content_type = model.indexed_get_toplevel_content_type()
@ -28,7 +28,7 @@ class Command(NoArgsCommand):
for obj in model.objects.all():
# Check if this object has an "object_indexed" function
if hasattr(obj, "object_indexed"):
if obj.object_indexed() == False:
if obj.object_indexed() is False:
continue
# Get key for this object
@ -38,7 +38,7 @@ class Command(NoArgsCommand):
if key in object_set:
# Conflict, work out who should get this space
# The object with the longest content type string gets the space
# Eg, "wagtailcore.Page-rca.StudentPage" kicks out "wagtailcore.Page"
# Eg, "wagtailcore.Page-myapp.BlogPost" kicks out "wagtailcore.Page"
if len(obj.indexed_get_content_type()) > len(object_set[key].indexed_get_content_type()):
# Take the spot
object_set[key] = obj

Wyświetl plik

@ -1,6 +1,6 @@
from django.db import models
from django.utils import timezone
from wagtail.wagtailcore.models import Page
from indexed import Indexed
from searcher import Searcher
import datetime
@ -79,7 +79,7 @@ class EditorsPick(models.Model):
page = models.ForeignKey('wagtailcore.Page')
sort_order = models.IntegerField(null=True, blank=True, editable=False)
description = models.TextField(blank=True)
class Meta:
ordering = ('sort_order', )
@ -98,4 +98,4 @@ class SearchTest(models.Model, Indexed):
class SearchTestChild(SearchTest):
extra_content = models.TextField()
indexed_fields = "extra_content"
indexed_fields = "extra_content"

Wyświetl plik

@ -1,9 +1,12 @@
from indexed import Indexed
from django.db import models
from django.conf import settings
import string
from pyelasticsearch.exceptions import ElasticHttpNotFoundError
from elasticutils import get_es, S
import string
from django.db import models
from django.conf import settings
from indexed import Indexed
class SearchResults(object):
@ -153,7 +156,7 @@ class Search(object):
# Check if this object has an "object_indexed" function
if hasattr(obj, "object_indexed"):
if obj.object_indexed() == False:
if obj.object_indexed() is False:
return False
return True
@ -203,7 +206,7 @@ class Search(object):
try:
self.es.delete(self.es_index, obj.indexed_get_content_type(), doc_id)
except ElasticHttpNotFoundError:
pass # Document doesn't exist, ignore this exception
pass # Document doesn't exist, ignore this exception
def search(self, query_string, model, fields=None, filters={}, prefetch_related=[]):
# Model must be a descendant of Indexed and be a django model
@ -240,4 +243,4 @@ class Search(object):
query = query.filter(**filters)
# Return search results
return SearchResults(model, query, prefetch_related=prefetch_related)
return SearchResults(model, query, prefetch_related=prefetch_related)

Wyświetl plik

@ -11,4 +11,4 @@ class Searcher(object):
search_kwargs = dict(model=cls, fields=self.fields, filters=self.filters)
search_kwargs.update(kwargs)
return Search().search(query_string, **search_kwargs)
return dosearch
return dosearch

Wyświetl plik

@ -1,6 +1,6 @@
from django.dispatch import Signal
from django.db.models.signals import post_save, post_delete
from django.db import models
from search import Search
from indexed import Indexed
@ -20,4 +20,4 @@ def register_signal_handlers():
# Loop through list and register signal handlers for each one
for model in indexed_models:
post_save.connect(post_save_signal_handler, sender=model)
post_delete.connect(post_delete_signal_handler, sender=model)
post_delete.connect(post_delete_signal_handler, sender=model)

Wyświetl plik

@ -1,7 +1,8 @@
from search import Search
import models
from django.test import TestCase
import models
from search import Search
class TestSearch(TestCase):
def test_search(self):
@ -36,16 +37,14 @@ class TestSearch(TestCase):
results = s.search("World", models.SearchTest)
self.assertEqual(len(results), 1)
# Searcher search
results = models.SearchTest.title_search("Hello")
self.assertEqual(len(results), 3)
# Ordinary search on child
results = s.search("Hello", models.SearchTestChild)
self.assertEqual(len(results), 1)
# Searcher search on child
results = models.SearchTestChild.title_search("Hello")
self.assertEqual(len(results), 1)
self.assertEqual(len(results), 1)

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns("wagtail.wagtailsearch.views",
urlpatterns = patterns(
"wagtail.wagtailsearch.views",
url(r"^editorspicks/$", "editorspicks.index", name="wagtailsearch_editorspicks_index"),
url(r"^editorspicks/add/$", "editorspicks.add", name="wagtailsearch_editorspicks_add"),
url(r"^editorspicks/(\d+)/$", "editorspicks.edit", name="wagtailsearch_editorspicks_edit"),

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns("wagtail.wagtailsearch.views.frontend",
urlpatterns = patterns(
"wagtail.wagtailsearch.views.frontend",
url(r"^$", "search", name="wagtailsearch_search"),
url(r"^suggest/$", "suggest", name="wagtailsearch_suggest"),
)

Wyświetl plik

@ -1,5 +1,6 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from wagtail.wagtailsearch import models, forms
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
@ -128,4 +129,4 @@ def delete(request, query_id):
return render(request, 'wagtailsearch/editorspicks/confirm_delete.html', {
'query': query,
})
})

Wyświetl plik

@ -1,11 +1,14 @@
import json
from django.conf import settings
from django.shortcuts import render
from django.http import HttpResponse
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailcore import models
from wagtail.wagtailsearch import Search
from wagtail.wagtailsearch.models import Query
import json
def search(request):
@ -65,4 +68,4 @@ def suggest(request):
return HttpResponse(json.dumps(suggestions))
else:
return HttpResponse("[]")
return HttpResponse("[]")

Wyświetl plik

@ -1,9 +1,10 @@
from django.shortcuts import get_object_or_404, render
from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.decorators import login_required
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailsearch import models
@ -39,15 +40,16 @@ def chooser(request, get_results=False):
# Render
if get_results:
return render(request, "wagtailsearch/queries/chooser/results.html", {
'queries': queries,
'queries': queries,
'is_searching': is_searching,
})
else:
return render_modal_workflow(request, 'wagtailsearch/queries/chooser/chooser.html', 'wagtailsearch/queries/chooser/chooser.js',{
return render_modal_workflow(request, 'wagtailsearch/queries/chooser/chooser.html', 'wagtailsearch/queries/chooser/chooser.js', {
'queries': queries,
'searchform': searchform,
'is_searching': False,
})
def chooserresults(request):
return chooser(request, get_results=True)
return chooser(request, get_results=True)

Wyświetl plik

@ -11,6 +11,7 @@ class BaseSnippetChooserPanel(BaseChooserPanel):
object_type_name = 'item'
_content_type = None
@classmethod
def content_type(cls):
if cls._content_type is None:
@ -38,6 +39,7 @@ class BaseSnippetChooserPanel(BaseChooserPanel):
content_type.model,
))
def SnippetChooserPanel(field_name, snippet_type):
return type('_SnippetChooserPanel', (BaseSnippetChooserPanel,), {
'field_name': field_name,

Wyświetl plik

@ -1,6 +1,8 @@
from django.contrib.auth.models import Permission
from wagtail.wagtailsnippets.models import get_snippet_content_types
def user_can_edit_snippet_type(user, content_type):
""" true if user has any permission related to this content type """
if user.is_active and user.is_superuser:

Wyświetl plik

@ -1,7 +1,8 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailsnippets.views',
urlpatterns = patterns(
'wagtail.wagtailsnippets.views',
url(r'^$', 'snippets.index', name='wagtailsnippets_index'),
url(r'^choose/(\w+)/(\w+)/$', 'chooser.choose', name='wagtailsnippets_choose'),

Wyświetl plik

@ -1,11 +1,13 @@
import json
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
import json
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailsnippets.views.snippets import get_content_type_from_url_params, get_snippet_type_name
@login_required
def choose(request, content_type_app_name, content_type_model_name):
content_type = get_content_type_from_url_params(content_type_app_name, content_type_model_name)
@ -14,7 +16,8 @@ def choose(request, content_type_app_name, content_type_model_name):
items = model.objects.all()
return render_modal_workflow(request,
return render_modal_workflow(
request,
'wagtailsnippets/chooser/choose.html', 'wagtailsnippets/chooser/choose.js',
{
'content_type': content_type,
@ -23,6 +26,7 @@ def choose(request, content_type_app_name, content_type_model_name):
}
)
@login_required
def chosen(request, content_type_app_name, content_type_model_name, id):
content_type = get_content_type_from_url_params(content_type_app_name, content_type_model_name)
@ -34,7 +38,8 @@ def chosen(request, content_type_app_name, content_type_model_name, id):
'string': unicode(item),
})
return render_modal_workflow(request,
return render_modal_workflow(
request,
None, 'wagtailsnippets/chooser/chosen.js',
{
'snippet_json': snippet_json,

Wyświetl plik

@ -7,12 +7,15 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from wagtail.wagtailsnippets.models import get_snippet_content_types
from wagtail.wagtailsnippets.permissions import user_can_edit_snippet_type
from wagtail.wagtailadmin.edit_handlers import ObjectList, extract_panel_definitions_from_model_class
from wagtail.wagtailsnippets.models import get_snippet_content_types
from wagtail.wagtailsnippets.permissions import user_can_edit_snippet_type
# == Helper functions ==
def get_snippet_type_name(content_type):
""" e.g. given the 'advert' content type, return ('Advert', 'Adverts') """
# why oh why is this so convoluted?
@ -22,6 +25,7 @@ def get_snippet_type_name(content_type):
force_text(opts.verbose_name_plural)
)
def get_snippet_type_description(content_type):
""" return the meta description of the class associated with the given content type """
opts = content_type.model_class()._meta
@ -30,6 +34,7 @@ def get_snippet_type_description(content_type):
except:
return ''
def get_content_type_from_url_params(app_name, model_name):
"""
retrieve a content type from an app_name / model_name combo.
@ -45,7 +50,10 @@ def get_content_type_from_url_params(app_name, model_name):
return content_type
SNIPPET_EDIT_HANDLERS = {}
def get_snippet_edit_handler(model):
if model not in SNIPPET_EDIT_HANDLERS:
panels = extract_panel_definitions_from_model_class(model)
@ -55,8 +63,10 @@ def get_snippet_edit_handler(model):
return SNIPPET_EDIT_HANDLERS[model]
# == Views ==
@login_required
def index(request):
snippet_types = [
@ -129,6 +139,7 @@ def create(request, content_type_app_name, content_type_model_name):
'edit_handler': edit_handler,
})
@login_required
def edit(request, content_type_app_name, content_type_model_name, id):
content_type = get_content_type_from_url_params(content_type_app_name, content_type_model_name)

Wyświetl plik

@ -6,9 +6,11 @@ from django.utils.translation import ugettext_lazy as _
# extend Django's UserCreationForm with an 'is_superuser' field
class UserCreationForm(BaseUserCreationForm):
required_css_class = "required"
is_superuser = forms.BooleanField(label=_("Administrator"), required=False,
is_superuser = forms.BooleanField(
label=_("Administrator"),
required=False,
help_text=_("If ticked, this user has the ability to manage user accounts.")
)
first_name = forms.CharField(required=True)
@ -43,26 +45,32 @@ class UserEditForm(forms.ModelForm):
'duplicate_username': _("A user with that username already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
username = forms.RegexField(
label=_("Username"),
max_length=30,
regex=r'^[\w.@+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"@/./+/-/_ only."),
help_text=_("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"@/./+/-/_ characters.")})
'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")
})
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
password1 = forms.CharField(label=_("Password"), required=False,
password1 = forms.CharField(
label=_("Password"),
required=False,
widget=forms.PasswordInput,
help_text=_("Leave blank if not changing."))
password2 = forms.CharField(label=_("Password confirmation"), required=False,
password2 = forms.CharField(
label=_("Password confirmation"), required=False,
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
is_superuser = forms.BooleanField(label=_("Administrator"), required=False,
is_superuser = forms.BooleanField(
label=_("Administrator"),
required=False,
help_text=_("Administrators have the ability to manage user accounts.")
)

Wyświetl plik

@ -1,6 +1,7 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('wagtail.wagtailusers.views',
urlpatterns = patterns(
'wagtail.wagtailusers.views',
url(r'^$', 'users.index', name='wagtailusers_index'),
url(r'^new/$', 'users.create', name='wagtailusers_create'),
url(r'^(\d+)/$', 'users.edit', name='wagtailusers_edit'),

Wyświetl plik

@ -6,6 +6,7 @@ from django.contrib import messages
from wagtail.wagtailusers.forms import UserCreationForm, UserEditForm
@permission_required('auth.change_user')
def index(request):
p = request.GET.get("p", 1)
@ -35,6 +36,7 @@ def index(request):
'ordering': ordering,
})
@permission_required('auth.change_user')
def create(request):
if request.POST:
@ -52,6 +54,7 @@ def create(request):
'form': form,
})
@permission_required('auth.change_user')
def edit(request, user_id):
user = get_object_or_404(User, id=user_id)