kopia lustrzana https://github.com/wagtail/wagtail
Merge branch 'master' of github.com:torchbox/wagtail
commit
a61a829c89
|
@ -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,), {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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={}):
|
||||
""""
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
.messages{
|
||||
position:relative;
|
||||
|
||||
z-index:5;
|
||||
|
||||
background-color:@color-grey-5;
|
||||
|
||||
ul{
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 %}
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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:])
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -2,6 +2,7 @@ from django import template
|
|||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def wagtailuserbar(context, cssfile=""):
|
||||
try:
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -30,4 +30,4 @@ def change_password(request):
|
|||
return render(request, 'wagtailadmin/account/change_password.html', {
|
||||
'form': form,
|
||||
'can_change_password': can_change_password,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from wagtail.wagtailcore.models import Site
|
||||
|
||||
|
||||
class SiteMiddleware(object):
|
||||
def process_request(self, request):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,6 +2,7 @@ from django import template
|
|||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def pageurl(context, page):
|
||||
"""
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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')
|
||||
)
|
||||
|
|
|
@ -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('_')
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -24,4 +24,4 @@ class Embed(models.Model):
|
|||
unique_together = ('url', 'max_width')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.url
|
||||
return self.url
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import re
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from wagtail.wagtailembeds.embeds import get_embed
|
||||
|
||||
|
||||
|
|
|
@ -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)')
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from PIL import Image
|
||||
|
||||
|
||||
def resize(image, size):
|
||||
"""
|
||||
resize image to the requested size, using highest quality settings
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}),
|
||||
|
|
|
@ -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'),
|
||||
])
|
||||
]
|
||||
]
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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("[]")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.")
|
||||
)
|
||||
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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)
|
||||
|
|
Ładowanie…
Reference in New Issue