Format fix

This commit is contained in:
Oskar Hahn 2013-04-16 10:04:28 +02:00
parent 56844d93f2
commit db1503ad7b
7 changed files with 47 additions and 59 deletions

View File

@ -19,24 +19,32 @@ from openslides.utils.person import PersonFormField, MultiplePersonFormField
from .models import Motion, Category from .models import Motion, Category
class BaseMotionForm(CleanHtmlFormMixin, forms.ModelForm, CssClassMixin): class BaseMotionForm(CleanHtmlFormMixin, CssClassMixin, forms.ModelForm):
"""Base FormClass for a Motion. """
Base FormClass for a Motion.
For it's own, it append the version data to the fields. For it's own, it append the version data to the fields.
The class can be mixed with the following mixins to add fields for the The class can be mixed with the following mixins to add fields for the
submitter, supporters etc. submitter, supporters etc.
""" """
clean_html_fields = ('text', 'reason')
title = forms.CharField(widget=forms.TextInput(), label=_("Title")) title = forms.CharField(widget=forms.TextInput(), label=_("Title"))
"""Title of the motion. Will be saved in a MotionVersion object.""" """
Title of the motion. Will be saved in a MotionVersion object.
"""
text = forms.CharField(widget=forms.Textarea(), label=_("Text")) text = forms.CharField(widget=forms.Textarea(), label=_("Text"))
"""Text of the motion. Will be saved in a MotionVersion object.""" """
Text of the motion. Will be saved in a MotionVersion object.
"""
reason = forms.CharField( reason = forms.CharField(
widget=forms.Textarea(), required=False, label=_("Reason")) widget=forms.Textarea(), required=False, label=_("Reason"))
"""Reason of the motion. will be saved in a MotionVersion object.""" """
Reason of the motion. will be saved in a MotionVersion object.
"""
class Meta: class Meta:
model = Motion model = Motion
@ -52,12 +60,6 @@ class BaseMotionForm(CleanHtmlFormMixin, forms.ModelForm, CssClassMixin):
self.initial['reason'] = self.motion.reason self.initial['reason'] = self.motion.reason
super(BaseMotionForm, self).__init__(*args, **kwargs) super(BaseMotionForm, self).__init__(*args, **kwargs)
def get_clean_html_fields(self):
'''
The fields 'text' and 'reason' contain HTML, clean them
'''
return ('text', 'reason',)
class MotionSubmitterMixin(forms.ModelForm): class MotionSubmitterMixin(forms.ModelForm):
"""Mixin to append the submitter field to a MotionForm.""" """Mixin to append the submitter field to a MotionForm."""

View File

@ -3,33 +3,33 @@
*/ */
$(function() { $(function() {
var ck_options = { var ck_options = {
// Using a custom CSS file allows us to specifically style elements entered // Using a custom CSS file allows us to specifically style elements entered
// using the editor. Using the CSS prefix class .ckeditor_html prevents these // using the editor. Using the CSS prefix class .ckeditor_html prevents these
// styles from meddling with the main layout // styles from meddling with the main layout
contentsCss: "/static/styles/ckeditor.css", contentsCss: "/static/styles/ckeditor.css",
bodyClass: "ckeditor_html", bodyClass: "ckeditor_html",
allowedContent: allowedContent:
'h1 h2 h3 pre blockquote b i u strike;' + 'h1 h2 h3 pre blockquote b i u strike;' +
// A workaround for the problem described in http://dev.ckeditor.com/ticket/10192 // A workaround for the problem described in http://dev.ckeditor.com/ticket/10192
// Hopefully, the problem will be solved in the final version of CKEditor 4.1 // Hopefully, the problem will be solved in the final version of CKEditor 4.1
// If so, then {margin-left} can be removed // If so, then {margin-left} can be removed
'p{margin-left};' + 'p{margin-left};' +
'a[!href];' + 'a[!href];' +
'table tr th td caption;' + 'table tr th td caption;' +
'ol ul li;' + 'ol ul li;' +
'span{!font-family};' + 'span{!font-family};' +
'span{!color};', 'span{!color};',
removePlugins: "save, print, preview, pagebreak, templates, showblocks, magicline", removePlugins: "save, print, preview, pagebreak, templates, showblocks, magicline",
// Not part of the standard package of CKEditor // Not part of the standard package of CKEditor
// http://ckeditor.com/addon/insertpre // http://ckeditor.com/addon/insertpre
extraPlugins: "insertpre", extraPlugins: "insertpre",
toolbar_Full: [ toolbar_Full: [
{ name: 'document', items : [ 'Source','-','Save','DocProps','Preview','Print','-','Templates' ] }, { name: 'document', items : [ 'Source','-','Save','DocProps','Preview','Print','-','Templates' ] },
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] }, { name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
@ -44,10 +44,6 @@ $(function() {
toolbar: 'Full' toolbar: 'Full'
}; };
// Override the tags 'strong' and 'em' so that reportlab can read it
CKEDITOR.config.coreStyles_bold = { element : 'b', overrides : 'strong' };
CKEDITOR.config.coreStyles_italic = { element : 'i', overrides : 'em' };
CKEDITOR.replace('id_text', ck_options); CKEDITOR.replace('id_text', ck_options);
CKEDITOR.replace('id_reason', ck_options); CKEDITOR.replace('id_reason', ck_options);
}); });

View File

@ -13,15 +13,16 @@
import bleach import bleach
from django import forms from django import forms
from django.views.generic.edit import FormMixin from django.utils.translation import ugettext_lazy
from django.utils.translation import ugettext_lazy as _
# Allowed tags, attributes and styles allowed in textareas edited with a JS # Allowed tags, attributes and styles allowed in textareas edited with a JS
# editor. Everything not in these whitelists is stripped. # editor. Everything not in these whitelists is stripped.
HTML_TAG_WHITELIST = ('a', HTML_TAG_WHITELIST = ('a',
'i', 'i',
'em',
'b', 'b',
'strong',
'ul', 'ul',
'ol', 'ol',
'li', 'li',
@ -36,11 +37,10 @@ HTML_TAG_WHITELIST = ('a',
'h3',) 'h3',)
HTML_ATTRIBUTES_WHITELIST = { HTML_ATTRIBUTES_WHITELIST = {
'*': ['style'],
'a': ['href'], 'a': ['href'],
} }
HTML_STYLES_WHITELIST = ('text-decoration',) HTML_STYLES_WHITELIST = ()
class CssClassMixin(object): class CssClassMixin(object):
@ -60,26 +60,27 @@ class LocalizedModelMultipleChoiceField(forms.ModelMultipleChoiceField):
c = [] c = []
for (id, text) in super(LocalizedModelMultipleChoiceField, self)._get_choices(): for (id, text) in super(LocalizedModelMultipleChoiceField, self)._get_choices():
text = text.split(' | ')[-1] text = text.split(' | ')[-1]
c.append((id, _(text))) c.append((id, ugettext_lazy(text)))
return c return c
choices = property(_localized_get_choices, forms.ChoiceField._set_choices) choices = property(_localized_get_choices, forms.ChoiceField._set_choices)
class CleanHtmlFormMixin(FormMixin): class CleanHtmlFormMixin(object):
''' """
A form mixin that pre-processes the form, cleaning up the HTML code found A form mixin that pre-processes the form, cleaning up the HTML code found
in the fields in clean_html. All HTML tags, attributes and styles not in the in the fields in clean_html. All HTML tags, attributes and styles not in the
whitelists are stripped from the output, leaving only the text content: whitelists are stripped from the output, leaving only the text content:
<table><tr><td>foo</td></tr></table> simply becomes 'foo' <table><tr><td>foo</td></tr></table> simply becomes 'foo'
''' """
clean_html_fields = ()
def get_clean_html_fields(self): def get_clean_html_fields(self):
''' """
the list of elements to strip of potential malicious HTML The list of elements to strip of potential malicious HTML.
''' """
return() return self.clean_html_fields
def clean(self): def clean(self):
cleaned_data = super(CleanHtmlFormMixin, self).clean() cleaned_data = super(CleanHtmlFormMixin, self).clean()
@ -89,7 +90,4 @@ class CleanHtmlFormMixin(FormMixin):
attributes=HTML_ATTRIBUTES_WHITELIST, attributes=HTML_ATTRIBUTES_WHITELIST,
styles=HTML_STYLES_WHITELIST, styles=HTML_STYLES_WHITELIST,
strip=True) strip=True)
# Needed for reportlab
cleaned_data[field] = cleaned_data[field].replace('<br>', '</br>')
return cleaned_data return cleaned_data

View File

@ -45,7 +45,6 @@ PAGE_WIDTH = defaultPageSize[0]
stylesheet = StyleSheet1() stylesheet = StyleSheet1()
stylesheet.add(ParagraphStyle( stylesheet.add(ParagraphStyle(
name='Normal', name='Normal',
#fontName='Ubuntu',
fontSize=10, fontSize=10,
leading=12, leading=12,
)) ))

View File

@ -1,12 +1,12 @@
# Requirements for OpenSlides Core # Requirements for OpenSlides Core
Django==1.5.1 Django==1.5.1
django-mptt==0.5.5 django-mptt==0.5.5
beautifulsoup4==4.1.3
bleach==1.2.1
pillow==2.0.0 pillow==2.0.0
qrcode==2.7 qrcode==2.7
reportlab==2.7 reportlab==2.7
tornado==3.0.1 tornado==3.0.1
bleach==1.2.1
beautifulsoup4==4.1.3
# required for travis # required for travis
Fabric==1.6.0 Fabric==1.6.0

0
tests/forms/__init__.py Normal file
View File

View File

@ -1,33 +1,26 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Unit test for OpenSlides __init__.py Test the openslides forms.
:copyright: 2011, 2012, 2013 by the OpenSlides team, see AUTHORS. :copyright: 2011, 2012, 2013 by the OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details. :license: GNU GPL, see LICENSE for more details.
""" """
from django.test import TestCase
from django import forms from django import forms
from django.db import models from django.db import models
from openslides.utils.test import TestCase
from openslides.utils.forms import CleanHtmlFormMixin from openslides.utils.forms import CleanHtmlFormMixin
from openslides.motion.models import Motion
class HtmlTestForm(CleanHtmlFormMixin, forms.Form): class HtmlTestForm(CleanHtmlFormMixin, forms.Form):
text = forms.CharField() text = forms.CharField()
text2 = forms.CharField() text2 = forms.CharField()
clean_html_fields = ('text',)
def get_clean_html_fields(self):
'''
The field 'text' contains HTML, clean it
'''
return ('text', )
class CleanHtmlTest(TestCase): class CleanHtmlTest(TestCase):
def clean_html(self, dirty='', clean=False): def clean_html(self, dirty='', clean=False):
form = HtmlTestForm({'text': dirty, 'text2': dirty}) form = HtmlTestForm({'text': dirty, 'text2': dirty})
form.is_valid() form.is_valid()
@ -38,31 +31,31 @@ class CleanHtmlTest(TestCase):
# Something was removed # Something was removed
else: else:
self.assertEqual(form.cleaned_data['text'], cleaned) self.assertEqual(form.cleaned_data['text'], clean)
# Field text2 has the same content, but is never passed through the # Field text2 has the same content, but is never passed through the
# HTML-cleanup and should never change # HTML-cleanup and should never change
self.assertEqual(form.cleaned_data['text2'], dirty) self.assertEqual(form.cleaned_data['text2'], dirty)
def test_clean_html(self): def test_clean_html(self):
''' """
Test that the correct HTML tags and attributes are removed Test that the correct HTML tags and attributes are removed
''' """
# Forbidden tags and attributes # Forbidden tags and attributes
self.clean_html('<script>do_evil();</script>', 'do_evil();') self.clean_html('<script>do_evil();</script>', 'do_evil();')
self.clean_html('<html>evil</html>', 'evil') self.clean_html('<html>evil</html>', 'evil')
self.clean_html('<a href="evil.com">good?</a>', 'good?')
self.clean_html('<p href="evil.com">good?</p>', '<p>good?</p>') self.clean_html('<p href="evil.com">good?</p>', '<p>good?</p>')
self.clean_html('<p onclick="javascript:evil();">Not evil</p>', '<p>Not evil</p>') self.clean_html('<p onclick="javascript:evil();">Not evil</p>', '<p>Not evil</p>')
self.clean_html('<div style="margin-top: 100000em;">evil</div>', 'evil') self.clean_html('<div style="margin-top: 100000em;">evil</div>', 'evil')
self.clean_html('<p style="font-weight:bold;">bad</p>', '<p style="">bad</p>') self.clean_html('<p style="font-weight:bold;">bad</p>', '<p>bad</p>')
self.clean_html('<table><tbody><tr><td>OK</td></tr></tbody></table>', 'OK')
self.clean_html('<blockquote>OK</blockquote>', 'OK')
self.clean_html('<p style="text-decoration: underline;">OK</p>', '<p>OK</p>')
# Allowed tags and attributes # Allowed tags and attributes
self.clean_html('<a href="evil.com">good?</a>')
self.clean_html('<p>OK</p>') self.clean_html('<p>OK</p>')
self.clean_html('<table><tbody><tr><td>OK</td></tr></tbody></table>')
self.clean_html('<p><strong>OK</strong></p>') self.clean_html('<p><strong>OK</strong></p>')
self.clean_html('<pre>OK</pre>') self.clean_html('<pre>OK</pre>')
self.clean_html('<blockquote>OK</blockquote>')
self.clean_html('<ul><li>OK</li></ul>') self.clean_html('<ul><li>OK</li></ul>')
self.clean_html('<p style="text-decoration: underline;">OK</p>')