Paginator der besser ins Design passt.
This commit is contained in:
@@ -3,11 +3,13 @@ Created on 28.09.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .countries import COUNTRIES
|
||||
from .html_cleaner import HtmlCleaner
|
||||
from .massmailer import MassMailer
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
STATUS_REJECTED, STATUS_WAITING, STATUS_PUBLISHED = -1, 0, 1
|
||||
STATUS_CHOICES = (
|
||||
@@ -22,6 +24,7 @@ class OverwriteStorage(FileSystemStorage):
|
||||
"""
|
||||
Returns same name for existing file and deletes existing file on save.
|
||||
"""
|
||||
|
||||
def _save(self, name, content):
|
||||
if self.exists(name):
|
||||
self.delete(name)
|
||||
|
||||
@@ -3,9 +3,10 @@ Created on 24.11.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
from django import forms
|
||||
import datetime
|
||||
|
||||
from django import forms
|
||||
|
||||
|
||||
class DateInput(forms.widgets.DateInput):
|
||||
input_type = 'date'
|
||||
@@ -13,9 +14,9 @@ class DateInput(forms.widgets.DateInput):
|
||||
|
||||
def __init__(self, attrs=None, **kwargs):
|
||||
forms.widgets.DateInput.__init__(self,
|
||||
attrs=attrs,
|
||||
format='%Y-%m-%d',
|
||||
**kwargs)
|
||||
attrs=attrs,
|
||||
format='%Y-%m-%d',
|
||||
**kwargs)
|
||||
|
||||
|
||||
class NumberInput(forms.widgets.Input):
|
||||
@@ -23,8 +24,7 @@ class NumberInput(forms.widgets.Input):
|
||||
|
||||
|
||||
class TimeInput(forms.widgets.Select):
|
||||
|
||||
def __init__(self, attrs=None,):
|
||||
def __init__(self, attrs=None, ):
|
||||
timeset = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
choices = [('', '-------')]
|
||||
while timeset < datetime.datetime(2000, 1, 2, 0, 0):
|
||||
@@ -37,7 +37,7 @@ class TimeInput(forms.widgets.Select):
|
||||
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
return forms.widgets.Select.render(self, name, value, attrs=attrs,
|
||||
choices=choices)
|
||||
choices=choices)
|
||||
|
||||
|
||||
class SplitDateTimeWidget(forms.widgets.MultiWidget):
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import re
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.http import HttpResponse
|
||||
from django.utils.encoding import smart_unicode, force_unicode
|
||||
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
from django.utils import simplejson as json
|
||||
|
||||
class LookupBase(object):
|
||||
|
||||
class LookupBase(object):
|
||||
@classmethod
|
||||
def name(cls):
|
||||
app_name = cls.__module__.split('.')[-2].lower()
|
||||
@@ -69,7 +72,6 @@ class LookupInvalid(Exception):
|
||||
|
||||
|
||||
class LookupRegistry(object):
|
||||
|
||||
def __init__(self):
|
||||
self._registry = {}
|
||||
|
||||
@@ -82,8 +84,8 @@ class LookupRegistry(object):
|
||||
self.validate(lookup)
|
||||
name = force_unicode(lookup.name())
|
||||
if name in self._registry:
|
||||
raise LookupAlreadyRegistered(u'The name %s is already registered'\
|
||||
% name)
|
||||
raise LookupAlreadyRegistered(u'The name %s is already registered' \
|
||||
% name)
|
||||
self._registry[name] = lookup
|
||||
|
||||
def unregister(self, lookup):
|
||||
|
||||
@@ -48,7 +48,7 @@ class AutoCompleteSelectField(Html5Mixin, django.forms.Field):
|
||||
self.allow_new = kwargs.pop('allow_new', False)
|
||||
if not kwargs['widget']:
|
||||
kwargs['widget'] = self.widget(lookup_class,
|
||||
allow_new=self.allow_new)
|
||||
allow_new=self.allow_new)
|
||||
super(AutoCompleteSelectField, self).__init__(*args, **kwargs)
|
||||
|
||||
def to_python(self, value):
|
||||
@@ -172,9 +172,9 @@ class PhoneField(Html5Mixin, django.forms.CharField):
|
||||
widget = widgets.PhoneInput
|
||||
|
||||
def __init__(self, regex=None, max_length=None, min_length=None,
|
||||
error_message=None, *args, **kwargs):
|
||||
error_message=None, *args, **kwargs):
|
||||
super(PhoneField, self).__init__(max_length, min_length,
|
||||
*args, **kwargs)
|
||||
*args, **kwargs)
|
||||
self._set_regex(u'^[0-9+-/ ]+$')
|
||||
|
||||
def _get_regex(self):
|
||||
@@ -184,7 +184,7 @@ class PhoneField(Html5Mixin, django.forms.CharField):
|
||||
regex = re.compile(regex, re.UNICODE)
|
||||
self._regex = regex
|
||||
if hasattr(self, '_regex_validator') \
|
||||
and self._regex_validator in self.validators:
|
||||
and self._regex_validator in self.validators:
|
||||
self.validators.remove(self._regex_validator)
|
||||
self._regex_validator = validators.RegexValidator(regex=regex)
|
||||
self.validators.append(self._regex_validator)
|
||||
@@ -193,68 +193,68 @@ class PhoneField(Html5Mixin, django.forms.CharField):
|
||||
|
||||
|
||||
class ReCaptchaField(django.forms.fields.CharField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.widget = widgets.ReCaptchaInput
|
||||
self.required = True
|
||||
super(ReCaptchaField, self).__init__(*args, **kwargs)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.widget = widgets.ReCaptchaInput
|
||||
self.required = True
|
||||
super(ReCaptchaField, self).__init__(*args, **kwargs)
|
||||
def _check_recaptcha(self, challenge_value, response_value, remote_ip):
|
||||
"""
|
||||
Submits a reCAPTCHA request for verification.
|
||||
Returns RecaptchaResponse for the request
|
||||
|
||||
def _check_recaptcha(self, challenge_value, response_value, remote_ip):
|
||||
"""
|
||||
Submits a reCAPTCHA request for verification.
|
||||
Returns RecaptchaResponse for the request
|
||||
@param challenge_value: value of recaptcha_challenge_field
|
||||
@param response_value: value of recaptcha_response_field
|
||||
@param remoteip -- the user's ip address
|
||||
|
||||
@param challenge_value: value of recaptcha_challenge_field
|
||||
@param response_value: value of recaptcha_response_field
|
||||
@param remoteip -- the user's ip address
|
||||
"""
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
"""
|
||||
import urllib
|
||||
import urllib2
|
||||
private_key = settings.RECAPTCHA_PRIVATE_KEY
|
||||
challenge_value = challenge_value.encode('utf-8')
|
||||
response_value = response_value.encode('utf-8')
|
||||
params = urllib.urlencode({
|
||||
'privatekey': private_key,
|
||||
'remoteip': remote_ip,
|
||||
'challenge': challenge_value,
|
||||
'response': response_value,
|
||||
})
|
||||
private_key = settings.RECAPTCHA_PRIVATE_KEY
|
||||
challenge_value = challenge_value.encode('utf-8')
|
||||
response_value = response_value.encode('utf-8')
|
||||
params = urllib.urlencode({
|
||||
'privatekey': private_key,
|
||||
'remoteip': remote_ip,
|
||||
'challenge': challenge_value,
|
||||
'response': response_value,
|
||||
})
|
||||
|
||||
request = urllib2.Request(
|
||||
url="http://www.google.com/recaptcha/api/verify",
|
||||
data=params,
|
||||
headers={
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
"User-agent": "reCAPTCHA Python"
|
||||
}
|
||||
)
|
||||
httpresp = urllib2.urlopen(request)
|
||||
request = urllib2.Request(
|
||||
url="http://www.google.com/recaptcha/api/verify",
|
||||
data=params,
|
||||
headers={
|
||||
"Content-type": "application/x-www-form-urlencoded",
|
||||
"User-agent": "reCAPTCHA Python"
|
||||
}
|
||||
)
|
||||
httpresp = urllib2.urlopen(request)
|
||||
|
||||
return_values = httpresp.read().splitlines()
|
||||
httpresp.close()
|
||||
return_values = httpresp.read().splitlines()
|
||||
httpresp.close()
|
||||
|
||||
return_code = return_values[0]
|
||||
if (return_code == "true"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return_code = return_values[0]
|
||||
if (return_code == "true"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def clean(self, values):
|
||||
challenge_value = values[0]
|
||||
response_value = values[1]
|
||||
super(ReCaptchaField, self).clean(response_value)
|
||||
if not challenge_value:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA challenge is missing.'))
|
||||
elif not response_value:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA solution is missing.'))
|
||||
elif self._check_recaptcha(challenge_value, response_value):
|
||||
return challenge_value
|
||||
else:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA solution was incorrect.'))
|
||||
def clean(self, values):
|
||||
challenge_value = values[0]
|
||||
response_value = values[1]
|
||||
super(ReCaptchaField, self).clean(response_value)
|
||||
if not challenge_value:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA challenge is missing.'))
|
||||
elif not response_value:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA solution is missing.'))
|
||||
elif self._check_recaptcha(challenge_value, response_value):
|
||||
return challenge_value
|
||||
else:
|
||||
raise util.ValidationError(
|
||||
_(u'The CAPTCHA solution was incorrect.'))
|
||||
|
||||
|
||||
class RegexField(Html5Mixin, django.forms.RegexField):
|
||||
|
||||
@@ -4,15 +4,13 @@ Created on 08.05.2011
|
||||
@author: christian
|
||||
"""
|
||||
from django.db import models
|
||||
from django.db.models import ForeignKey, Model, SET_NULL # @UnusedImport
|
||||
from django.db.models import SET_DEFAULT, ManyToManyField # @UnusedImport
|
||||
from django.db.models import ForeignKey # @UnusedImport
|
||||
from django.utils import six
|
||||
|
||||
from . import forms, widgets
|
||||
|
||||
|
||||
class BooleanField(models.BooleanField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.BooleanField}
|
||||
defaults.update(kwargs)
|
||||
@@ -20,7 +18,6 @@ class BooleanField(models.BooleanField):
|
||||
|
||||
|
||||
class CharField(models.CharField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.CharField}
|
||||
defaults.update(kwargs)
|
||||
@@ -28,7 +25,6 @@ class CharField(models.CharField):
|
||||
|
||||
|
||||
class DateField(models.DateField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'form_class': forms.DateField}
|
||||
@@ -37,7 +33,6 @@ class DateField(models.DateField):
|
||||
|
||||
|
||||
class DateTimeField(models.DateTimeField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.DateTimeField}
|
||||
defaults.update(kwargs)
|
||||
@@ -52,7 +47,6 @@ class EmailField(models.EmailField):
|
||||
|
||||
|
||||
class FileField(models.FileField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.FileField}
|
||||
defaults.update(kwargs)
|
||||
@@ -60,7 +54,6 @@ class FileField(models.FileField):
|
||||
|
||||
|
||||
class ForeignKey(models.ForeignKey):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
db = kwargs.pop('using', None)
|
||||
if isinstance(self.rel.to, six.string_types):
|
||||
@@ -83,7 +76,6 @@ class ImageField(models.ImageField):
|
||||
|
||||
|
||||
class IntegerField(models.IntegerField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.IntegerField}
|
||||
defaults.update(kwargs)
|
||||
@@ -91,7 +83,6 @@ class IntegerField(models.IntegerField):
|
||||
|
||||
|
||||
class NullBooleanField(models.NullBooleanField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.BooleanField}
|
||||
defaults.update(kwargs)
|
||||
@@ -99,7 +90,6 @@ class NullBooleanField(models.NullBooleanField):
|
||||
|
||||
|
||||
class PositiveSmallIntegerField(models.PositiveSmallIntegerField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'form_class': forms.IntegerField,
|
||||
@@ -111,7 +101,6 @@ class PositiveSmallIntegerField(models.PositiveSmallIntegerField):
|
||||
|
||||
|
||||
class PositiveIntegerField(models.IntegerField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'form_class': forms.IntegerField,
|
||||
@@ -122,7 +111,6 @@ class PositiveIntegerField(models.IntegerField):
|
||||
|
||||
|
||||
class SlugField(models.SlugField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.SlugField}
|
||||
defaults.update(kwargs)
|
||||
@@ -130,9 +118,7 @@ class SlugField(models.SlugField):
|
||||
|
||||
|
||||
class TextField(models.TextField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
|
||||
defaults = {
|
||||
'form_class': forms.CharField,
|
||||
'widget': widgets.Textarea
|
||||
@@ -142,7 +128,6 @@ class TextField(models.TextField):
|
||||
|
||||
|
||||
class URLField(models.URLField):
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.URLField}
|
||||
defaults.update(kwargs)
|
||||
|
||||
@@ -4,6 +4,7 @@ Created on 05.08.2011
|
||||
@author: christian
|
||||
"""
|
||||
from django.http import Http404
|
||||
|
||||
from . import registry
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
class AutoCompleteWidget(widgets.TextInput):
|
||||
|
||||
def __init__(self, lookup_class, attrs=None, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
self.allow_new = kwargs.pop('allow_new', False)
|
||||
@@ -29,7 +28,8 @@ class AutoCompleteWidget(widgets.TextInput):
|
||||
self.qs.update(qs_dict)
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
||||
attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs,
|
||||
**kwargs) # @IgnorePep8
|
||||
url = self.lookup_class.url()
|
||||
if self.qs:
|
||||
url = '%s?%s' % (url, urlencode(self.qs))
|
||||
@@ -40,9 +40,9 @@ class AutoCompleteWidget(widgets.TextInput):
|
||||
|
||||
|
||||
class AutoComboboxWidget(AutoCompleteWidget):
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
||||
attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs,
|
||||
**kwargs) # @IgnorePep8
|
||||
attrs[u'data-selectable-type'] = 'combobox'
|
||||
return attrs
|
||||
|
||||
@@ -66,7 +66,8 @@ class DateTimeInput(widgets.MultiWidget):
|
||||
A Widget that splits datetime input into two <input type="text"> boxes.
|
||||
"""
|
||||
|
||||
def __init__(self, attrs=None, date_format='%Y-%m-%d', time_format='%H:%M'): # @IgnorePep8
|
||||
def __init__(self, attrs=None, date_format='%Y-%m-%d',
|
||||
time_format='%H:%M'): # @IgnorePep8
|
||||
widgets = (
|
||||
DateInput(attrs=attrs, date_format=date_format),
|
||||
TimeInput(attrs=attrs, time_format=time_format)
|
||||
@@ -92,7 +93,8 @@ class CheckboxInput(widgets.CheckboxInput):
|
||||
result = False
|
||||
if result:
|
||||
final_attrs['checked'] = 'checked'
|
||||
if not (value is True or value is False or value is None or value == ''): # @IgnorePep8
|
||||
if not (
|
||||
value is True or value is False or value is None or value == ''): # @IgnorePep8
|
||||
# Only add the 'value' attribute if a value is non-empty.
|
||||
final_attrs['value'] = force_unicode(value)
|
||||
|
||||
@@ -132,12 +134,13 @@ class ReCaptchaInput(widgets.Widget):
|
||||
src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s">
|
||||
</script><noscript><iframe
|
||||
src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s"
|
||||
height="300" width="500" frameborder="0"></iframe><br /><textarea
|
||||
height="130" width="500"></iframe><br /><textarea
|
||||
name="recaptcha_challenge_field" rows="3" cols="40"></textarea><input
|
||||
type="hidden" name="recaptcha_response_field" value="manual_challenge">
|
||||
</noscript>"""
|
||||
return mark_safe(javascript % {'public_key':
|
||||
settings.RECAPTCHA_PUBLIC_KEY, 'theme': 'red'})
|
||||
settings.RECAPTCHA_PUBLIC_KEY,
|
||||
'theme': 'red'})
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
return [data.get(self.recaptcha_challenge_name, None),
|
||||
@@ -145,13 +148,11 @@ class ReCaptchaInput(widgets.Widget):
|
||||
|
||||
|
||||
class SelectableMultiWidget(widgets.MultiWidget):
|
||||
|
||||
def update_query_parameters(self, qs_dict):
|
||||
self.widgets[0].update_query_parameters(qs_dict)
|
||||
|
||||
|
||||
class Textarea(widgets.Widget):
|
||||
|
||||
def __init__(self, attrs=None):
|
||||
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
||||
default_attrs = {'cols': '40', 'rows': '10'}
|
||||
@@ -163,7 +164,9 @@ class Textarea(widgets.Widget):
|
||||
value = '' if value is None else value
|
||||
final_attrs = self.build_attrs(attrs, name=name)
|
||||
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
|
||||
conditional_escape(force_unicode(value))))
|
||||
conditional_escape(
|
||||
force_unicode(
|
||||
value))))
|
||||
|
||||
|
||||
class TextInput(widgets.TextInput):
|
||||
@@ -192,7 +195,6 @@ class URLInput(widgets.Input):
|
||||
|
||||
|
||||
class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
|
||||
|
||||
def __init__(self, lookup_class, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs)
|
||||
@@ -221,21 +223,22 @@ class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
|
||||
return mark_safe(u'\n'.join(inputs))
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
||||
attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs,
|
||||
**kwargs) # @IgnorePep8
|
||||
attrs[u'data-selectable-type'] = 'hidden-multiple'
|
||||
return attrs
|
||||
|
||||
|
||||
class AutoCompleteSelectMultipleWidget(SelectableMultiWidget):
|
||||
|
||||
def __init__(self, lookup_class, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
widgets = [
|
||||
AutoCompleteWidget(lookup_class, allow_new=False,
|
||||
attrs={u'data-selectable-multiple': 'true'}),
|
||||
attrs={u'data-selectable-multiple': 'true'}),
|
||||
LookupMultipleHiddenInput(lookup_class)
|
||||
]
|
||||
super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8
|
||||
super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args,
|
||||
**kwargs) # @IgnorePep8
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
||||
@@ -244,19 +247,20 @@ class AutoCompleteSelectMultipleWidget(SelectableMultiWidget):
|
||||
if value and not hasattr(value, '__iter__'):
|
||||
value = [value]
|
||||
value = [u'', value]
|
||||
return super(AutoCompleteSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8
|
||||
return super(AutoCompleteSelectMultipleWidget, self).render(name, value,
|
||||
attrs) # @IgnorePep8
|
||||
|
||||
|
||||
class AutoComboboxSelectMultipleWidget(SelectableMultiWidget):
|
||||
|
||||
def __init__(self, lookup_class, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
widgets = [
|
||||
AutoComboboxWidget(lookup_class, allow_new=False,
|
||||
attrs={u'data-selectable-multiple': 'true'}),
|
||||
attrs={u'data-selectable-multiple': 'true'}),
|
||||
LookupMultipleHiddenInput(lookup_class)
|
||||
]
|
||||
super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8
|
||||
super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args,
|
||||
**kwargs) # @IgnorePep8
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
||||
@@ -265,11 +269,11 @@ class AutoComboboxSelectMultipleWidget(SelectableMultiWidget):
|
||||
if value and not hasattr(value, '__iter__'):
|
||||
value = [value]
|
||||
value = [u'', value]
|
||||
return super(AutoComboboxSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8
|
||||
return super(AutoComboboxSelectMultipleWidget, self).render(name, value,
|
||||
attrs) # @IgnorePep8
|
||||
|
||||
|
||||
class AutoCompleteSelectWidget(SelectableMultiWidget):
|
||||
|
||||
def __init__(self, lookup_class, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
self.allow_new = kwargs.pop('allow_new', False)
|
||||
@@ -277,7 +281,8 @@ class AutoCompleteSelectWidget(SelectableMultiWidget):
|
||||
AutoCompleteWidget(lookup_class, allow_new=self.allow_new),
|
||||
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
||||
]
|
||||
super(AutoCompleteSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8
|
||||
super(AutoCompleteSelectWidget, self).__init__(widget_set, *args,
|
||||
**kwargs) # @IgnorePep8
|
||||
|
||||
def decompress(self, value):
|
||||
if value:
|
||||
@@ -294,7 +299,6 @@ class AutoCompleteSelectWidget(SelectableMultiWidget):
|
||||
|
||||
|
||||
class AutoComboboxSelectWidget(SelectableMultiWidget):
|
||||
|
||||
def __init__(self, lookup_class, *args, **kwargs):
|
||||
self.lookup_class = lookup_class
|
||||
self.allow_new = kwargs.pop('allow_new', False)
|
||||
@@ -302,7 +306,8 @@ class AutoComboboxSelectWidget(SelectableMultiWidget):
|
||||
AutoComboboxWidget(lookup_class, allow_new=self.allow_new),
|
||||
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
||||
]
|
||||
super(AutoComboboxSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8
|
||||
super(AutoComboboxSelectWidget, self).__init__(widget_set, *args,
|
||||
**kwargs) # @IgnorePep8
|
||||
|
||||
def decompress(self, value):
|
||||
if value:
|
||||
|
||||
@@ -8,13 +8,19 @@ from BeautifulSoup import BeautifulSoup
|
||||
|
||||
class HtmlCleaner(object):
|
||||
ACCEPTABLE_ELEMENTS = ['a', 'abbr', 'acronym', 'address', 'area', 'b',
|
||||
'big', 'blockquote', 'br', 'button', 'caption', 'center', 'cite',
|
||||
'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl',
|
||||
'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i',
|
||||
'img', 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol',
|
||||
'p', 'pre', 'q', 's', 'samp', 'small', 'span', 'strike',
|
||||
'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th',
|
||||
'thead', 'tr', 'tt', 'u', 'ul', 'var']
|
||||
'big', 'blockquote', 'br', 'button', 'caption',
|
||||
'center', 'cite',
|
||||
'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir',
|
||||
'div', 'dl',
|
||||
'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5',
|
||||
'h6', 'hr', 'i',
|
||||
'img', 'ins', 'kbd', 'label', 'legend', 'li', 'map',
|
||||
'menu', 'ol',
|
||||
'p', 'pre', 'q', 's', 'samp', 'small', 'span',
|
||||
'strike',
|
||||
'strong', 'sub', 'sup', 'table', 'tbody', 'td',
|
||||
'tfoot', 'th',
|
||||
'thead', 'tr', 'tt', 'u', 'ul', 'var']
|
||||
|
||||
ACCEPTABELE_ATTRIBUTES = [
|
||||
'abbr', 'accept', 'accept-charset', 'accesskey',
|
||||
|
||||
@@ -22,10 +22,10 @@ class Command(BaseCommand):
|
||||
help = _("Reads raw CSS from stdin, and writes compressed CSS to stdout.")
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('-w', '--wrap',
|
||||
type='int',
|
||||
default=None,
|
||||
metavar='N',
|
||||
help="Wrap output to approximately N chars per line."),
|
||||
type='int',
|
||||
default=None,
|
||||
metavar='N',
|
||||
help="Wrap output to approximately N chars per line."),
|
||||
)
|
||||
|
||||
def remove_comments(self, css):
|
||||
@@ -65,7 +65,6 @@ class Command(BaseCommand):
|
||||
"""Remove unnecessary whitespace characters."""
|
||||
|
||||
def pseudoclasscolon(css):
|
||||
|
||||
"""
|
||||
Prevents 'p :link' from becoming 'p:link'.
|
||||
|
||||
@@ -157,13 +156,15 @@ class Command(BaseCommand):
|
||||
def condense_hex_colors(self, css):
|
||||
"""Shorten colors from #AABBCC to #ABC where possible."""
|
||||
|
||||
regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
|
||||
regex = re.compile(
|
||||
r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
|
||||
match = regex.search(css)
|
||||
while match:
|
||||
first = match.group(3) + match.group(5) + match.group(7)
|
||||
second = match.group(4) + match.group(6) + match.group(8)
|
||||
if first.lower() == second.lower():
|
||||
css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first)
|
||||
css = css.replace(match.group(),
|
||||
match.group(1) + match.group(2) + '#' + first)
|
||||
match = regex.search(css, match.end() - 3)
|
||||
else:
|
||||
match = regex.search(css, match.end())
|
||||
@@ -235,7 +236,8 @@ class Command(BaseCommand):
|
||||
css = ''
|
||||
"""Read each .css file in the css_input directory,
|
||||
and append their content"""
|
||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)), '*.css'):
|
||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
|
||||
'*.css'):
|
||||
print ' Adding: %s' % file_name
|
||||
with open(os.path.join(css_input, file_name), 'r') as css_file:
|
||||
css += css_file.read()
|
||||
|
||||
@@ -3,13 +3,13 @@ Created on 06.06.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
import os
|
||||
import fnmatch
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.translation import ugettext as _
|
||||
from optparse import make_option
|
||||
import os, re, fnmatch
|
||||
from scss import parser
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@@ -22,13 +22,13 @@ class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
CSS_ROOT = os.path.join(settings.STATICFILES_DIRS[0], 'css')
|
||||
for site in Site.objects.all():
|
||||
css_input = os.path.join(CSS_ROOT, site.domain)
|
||||
css_input = os.path.join(CSS_ROOT, site.domain)
|
||||
css_output = '%s/%s.css' % (CSS_ROOT, site.domain.replace('.', '_'))
|
||||
|
||||
print _("Compressing CSS for %s") % site.name
|
||||
print "Input Dir: %s" % css_input
|
||||
print "Output File: %s" % css_output
|
||||
|
||||
|
||||
try:
|
||||
os.makedirs(css_input)
|
||||
except OSError:
|
||||
@@ -36,11 +36,12 @@ class Command(BaseCommand):
|
||||
css = ''
|
||||
"""Read each .css file in the css_input directory,
|
||||
and append their content"""
|
||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)), '*.css'):
|
||||
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
|
||||
'*.css'):
|
||||
print ' Adding: %s' % file_name
|
||||
with open(os.path.join(css_input, file_name), 'r') as css_file:
|
||||
css += css_file.read()
|
||||
with open(css_output, 'w') as css_file:
|
||||
css_file.write(self.compress(css))
|
||||
#file.write(css)
|
||||
# file.write(css)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
|
||||
from django.core import mail
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.sites.models import Site
|
||||
@@ -66,7 +67,7 @@ class MassMailer(object):
|
||||
for recipient in self.recipients:
|
||||
mail_context['recipient'] = recipient
|
||||
mail_to = "%s %s <%s>" % (recipient.first_name,
|
||||
recipient.last_name, recipient.email)
|
||||
recipient.last_name, recipient.email)
|
||||
message = mail.EmailMultiAlternatives(
|
||||
subject=self.subject,
|
||||
body=self.txt_template.render(mail_context),
|
||||
@@ -92,7 +93,7 @@ class MassMailer(object):
|
||||
return True
|
||||
else:
|
||||
self.log.info('Sending eMail "%s" to %d people', self.subject,
|
||||
len(self.mail_queue))
|
||||
len(self.mail_queue))
|
||||
self.log.debug(self.recipients)
|
||||
|
||||
self.open_smtp_connection()
|
||||
|
||||
@@ -20,13 +20,16 @@ class LoginRequiredMixin(object):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_authenticated():
|
||||
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
return super(LoginRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception: # if an exception was desired
|
||||
return http.HttpResponseForbidden() # return a forbidden response.
|
||||
else:
|
||||
messages.error(request, _("You need to be logged in"))
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
|
||||
|
||||
class PermissionRequiredMixin(object):
|
||||
"""
|
||||
@@ -60,18 +63,23 @@ class PermissionRequiredMixin(object):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
# Verify class settings
|
||||
if self.permission_required is None or len(self.permission_required.split(".")) != 2:
|
||||
raise ImproperlyConfigured("'PermissionRequiredMixin' requires 'permission_required' attribute to be set.")
|
||||
if self.permission_required is None or len(
|
||||
self.permission_required.split(".")) != 2:
|
||||
raise ImproperlyConfigured(
|
||||
"'PermissionRequiredMixin' requires 'permission_required' attribute to be set.")
|
||||
has_permission = request.user.has_perm(self.permission_required)
|
||||
|
||||
if has_permission:
|
||||
return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
return super(PermissionRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception:
|
||||
return http.HttpResponseForbidden()
|
||||
else:
|
||||
messages.warning(request, self.permission_failed_message)
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
|
||||
|
||||
class SuperuserRequiredMixin(object):
|
||||
"""
|
||||
@@ -83,10 +91,13 @@ class SuperuserRequiredMixin(object):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_superuser: # If the user is a standard user,
|
||||
return super(SuperuserRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
return super(SuperuserRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception: # *and* if an exception was desired
|
||||
return http.HttpResponseForbidden() # return a forbidden response.
|
||||
else:
|
||||
messages.error(request, _("You don't have the permissions for this"))
|
||||
messages.error(request,
|
||||
_("You don't have the permissions for this"))
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect("%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
|
||||
@@ -12,6 +12,7 @@ import markdown
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter(name='markdown', is_safe=True)
|
||||
def markdown_filter(value, arg=''):
|
||||
"""
|
||||
@@ -41,7 +42,8 @@ def markdown_filter(value, arg=''):
|
||||
if extensions and extensions[0] == "safe":
|
||||
extensions = extensions[1:]
|
||||
return mark_safe(markdown.markdown(
|
||||
force_text(value), extensions, safe_mode=True, enable_attributes=False))
|
||||
force_text(value), extensions, safe_mode=True,
|
||||
enable_attributes=False))
|
||||
else:
|
||||
return mark_safe(markdown.markdown(
|
||||
force_text(value), extensions, safe_mode=False))
|
||||
|
||||
Reference in New Issue
Block a user