Added clean methods stripping withespaces

This commit is contained in:
Marc 2014-10-21 16:13:18 +00:00
parent 147c1d0dd6
commit 5237a4130f
13 changed files with 69 additions and 11 deletions

View File

@ -158,3 +158,6 @@ textwrap.dedent( \\)
* better modeling of the interdependency between webapps and websites (settings) * better modeling of the interdependency between webapps and websites (settings)
* webapp options cfig agnostic * webapp options cfig agnostic
* Disable menu on tests, fucking overlapping
* service.name / verbose_name instead of .description ?

View File

@ -58,6 +58,10 @@ class Account(auth.AbstractBaseUser):
def get_main(cls): def get_main(cls):
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK) return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
def clean(self):
self.first_name = self.first_name.strip()
self.last_name = self.last_name.strip()
def disable(self): def disable(self):
self.is_active = False self.is_active = False
self.save(update_fields=['is_active']) self.save(update_fields=['is_active'])

View File

@ -49,5 +49,14 @@ class Contact(models.Model):
def __unicode__(self): def __unicode__(self):
return self.short_name return self.short_name
def clean(self):
self.short_name = self.short_name.strip()
self.full_name = self.full_name.strip()
self.phone = self.phone.strip()
self.phone2 = self.phone2.strip()
self.address = self.address.strip()
self.city = self.city.strip()
self.country = self.country.strip()
accounts.register(Contact) accounts.register(Contact)

View File

@ -2,6 +2,7 @@ import re
import textwrap import textwrap
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from orchestra.apps.orchestration import ServiceController from orchestra.apps.orchestration import ServiceController
from orchestra.apps.resources import ServiceMonitor from orchestra.apps.resources import ServiceMonitor
@ -135,6 +136,7 @@ class MailmanBackend(ServiceController):
class MailmanTraffic(ServiceMonitor): class MailmanTraffic(ServiceMonitor):
model = 'lists.List' model = 'lists.List'
resource = ServiceMonitor.TRAFFIC resource = ServiceMonitor.TRAFFIC
verbose_name = _("Mailman traffic")
def prepare(self): def prepare(self):
current_date = timezone.localtime(self.current_date) current_date = timezone.localtime(self.current_date)
@ -168,3 +170,18 @@ class MailmanTraffic(ServiceMonitor):
'object_id': mail_list.pk, 'object_id': mail_list.pk,
'last_date': last_date.strftime("%b %d %H:%M:%S"), 'last_date': last_date.strftime("%b %d %H:%M:%S"),
} }
class MailmanTraffic(ServiceMonitor):
model = 'lists.List'
verbose_name = _("Mailman subscribers")
def monitor(self, mail_list):
context = self.get_context(mail_list)
self.append('echo %(object_id)i $(list_members %(list_name)s | wc -l)' % context)
def get_context(self, mail_list):
return {
'list_name': mail_list.name,
'object_id': mail_list.pk,
}

View File

@ -11,11 +11,14 @@ from .models import Address, Mailbox
class MailboxForm(forms.ModelForm): class MailboxForm(forms.ModelForm):
""" hacky form for adding reverse M2M form field for Mailbox.addresses """ """ hacky form for adding reverse M2M form field for Mailbox.addresses """
# TODO keep track of this ticket for future reimplementation
# https://code.djangoproject.com/ticket/897
addresses = forms.ModelMultipleChoiceField(queryset=Address.objects, required=False, addresses = forms.ModelMultipleChoiceField(queryset=Address.objects, required=False,
widget=widgets.FilteredSelectMultiple(verbose_name=_('Pizzas'), is_stacked=False)) widget=widgets.FilteredSelectMultiple(verbose_name=_('Pizzas'), is_stacked=False))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MailboxForm, self).__init__(*args, **kwargs) super(MailboxForm, self).__init__(*args, **kwargs)
# Hack the widget in order to display add button
field = AttrDict(**{ field = AttrDict(**{
'to': Address, 'to': Address,
'get_related_field': lambda: AttrDict(name='id'), 'get_related_field': lambda: AttrDict(name='id'),
@ -23,6 +26,8 @@ class MailboxForm(forms.ModelForm):
widget = self.fields['addresses'].widget widget = self.fields['addresses'].widget
self.fields['addresses'].widget = widgets.RelatedFieldWidgetWrapper(widget, field, self.fields['addresses'].widget = widgets.RelatedFieldWidgetWrapper(widget, field,
self.modeladmin.admin_site, can_add_related=True) self.modeladmin.admin_site, can_add_related=True)
# Filter related addresses by account
old_render = self.fields['addresses'].widget.render old_render = self.fields['addresses'].widget.render
def render(*args, **kwargs): def render(*args, **kwargs):
output = old_render(*args, **kwargs) output = old_render(*args, **kwargs)
@ -44,7 +49,6 @@ class MailboxForm(forms.ModelForm):
return custom_filtering return custom_filtering
class MailboxChangeForm(UserChangeForm, MailboxForm): class MailboxChangeForm(UserChangeForm, MailboxForm):
pass pass
@ -66,4 +70,3 @@ class AddressForm(forms.ModelForm):
cleaned_data = super(AddressForm, self).clean() cleaned_data = super(AddressForm, self).clean()
if not cleaned_data.get('mailboxes', True) and not cleaned_data['forward']: if not cleaned_data.get('mailboxes', True) and not cleaned_data['forward']:
raise forms.ValidationError(_("Mailboxes or forward address should be provided")) raise forms.ValidationError(_("Mailboxes or forward address should be provided"))

View File

@ -24,12 +24,24 @@ class SEPADirectDebitForm(PluginDataForm):
name = forms.CharField(max_length=128, label=_("Name"), name = forms.CharField(max_length=128, label=_("Name"),
widget=forms.TextInput(attrs={'size': '50'})) widget=forms.TextInput(attrs={'size': '50'}))
def clean_iban(self):
return self.cleaned_data['iban'].strip()
def clean_name(self):
return self.cleaned_data['name'].strip()
class SEPADirectDebitSerializer(serializers.Serializer): class SEPADirectDebitSerializer(serializers.Serializer):
iban = serializers.CharField(label='IBAN', validators=[IBANValidator()], iban = serializers.CharField(label='IBAN', validators=[IBANValidator()],
min_length=min(IBAN_COUNTRY_CODE_LENGTH.values()), max_length=34) min_length=min(IBAN_COUNTRY_CODE_LENGTH.values()), max_length=34)
name = serializers.CharField(label=_("Name"), max_length=128) name = serializers.CharField(label=_("Name"), max_length=128)
def clean_iban(self, attrs, source):
return attrs[source].strip()
def clean_name(self, attrs, source):
return attrs[source].strip()
class SEPADirectDebit(PaymentMethod): class SEPADirectDebit(PaymentMethod):
verbose_name = _("SEPA Direct Debit") verbose_name = _("SEPA Direct Debit")

View File

@ -18,7 +18,7 @@ class ServiceMonitor(ServiceBackend):
abstract = True abstract = True
@classmethod @classmethod
def get_backends(cls): def get_plugins(cls):
""" filter controller classes """ """ filter controller classes """
return [ return [
plugin for plugin in cls.plugins if ServiceMonitor in plugin.__mro__ plugin for plugin in cls.plugins if ServiceMonitor in plugin.__mro__

View File

@ -61,4 +61,4 @@ def compute_resource_usage(data):
has_result = True has_result = True
else: else:
raise NotImplementedError("%s support not implemented" % data.period) raise NotImplementedError("%s support not implemented" % data.period)
return result/resource.scale if has_result else None return result/resource.get_scale() if has_result else None

View File

@ -1,12 +1,12 @@
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.apps import apps from django.apps import apps
from django.core import validators
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from djcelery.models import PeriodicTask, CrontabSchedule from djcelery.models import PeriodicTask, CrontabSchedule
from orchestra.core import validators
from orchestra.models import queryset, fields from orchestra.models import queryset, fields
from . import helpers from . import helpers
@ -36,8 +36,7 @@ class Resource(models.Model):
name = models.CharField(_("name"), max_length=32, name = models.CharField(_("name"), max_length=32,
help_text=_('Required. 32 characters or fewer. Lowercase letters, ' help_text=_('Required. 32 characters or fewer. Lowercase letters, '
'digits and hyphen only.'), 'digits and hyphen only.'),
validators=[validators.RegexValidator(r'^[a-z0-9_\-]+$', validators=[validators.validate_name])
_('Enter a valid name.'), 'invalid')])
verbose_name = models.CharField(_("verbose name"), max_length=256) verbose_name = models.CharField(_("verbose name"), max_length=256)
content_type = models.ForeignKey(ContentType, content_type = models.ForeignKey(ContentType,
help_text=_("Model where this resource will be hooked.")) help_text=_("Model where this resource will be hooked."))
@ -57,7 +56,7 @@ class Resource(models.Model):
"For example GB, KB or subscribers")) "For example GB, KB or subscribers"))
scale = models.PositiveIntegerField(_("scale"), scale = models.PositiveIntegerField(_("scale"),
help_text=_("Scale in which this resource monitoring resoults should " help_text=_("Scale in which this resource monitoring resoults should "
"be prorcessed to match with unit.")) "be prorcessed to match with unit. e.g. <tt>10**9</tt>"))
disable_trigger = models.BooleanField(_("disable trigger"), default=False, disable_trigger = models.BooleanField(_("disable trigger"), default=False,
help_text=_("Disables monitors exeeded and recovery triggers")) help_text=_("Disables monitors exeeded and recovery triggers"))
crontab = models.ForeignKey(CrontabSchedule, verbose_name=_("crontab"), crontab = models.ForeignKey(CrontabSchedule, verbose_name=_("crontab"),
@ -114,6 +113,9 @@ class Resource(models.Model):
args=[self.pk] args=[self.pk]
).delete() ).delete()
def get_scale(self):
return eval(self.scale)
class ResourceData(models.Model): class ResourceData(models.Model):
""" Stores computed resource usage and allocation """ """ Stores computed resource usage and allocation """

View File

@ -28,6 +28,9 @@ class Plan(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
def clean(self):
self.name = self.name.strip()
class ContractedPlan(models.Model): class ContractedPlan(models.Model):
plan = models.ForeignKey(Plan, verbose_name=_("plan"), related_name='contracts') plan = models.ForeignKey(Plan, verbose_name=_("plan"), related_name='contracts')
@ -215,6 +218,7 @@ class Service(models.Model):
return ServiceHandler(self) return ServiceHandler(self)
def clean(self): def clean(self):
self.description = self.description.strip()
content_type = self.handler.get_content_type() content_type = self.handler.get_content_type()
if self.content_type != content_type: if self.content_type != content_type:
ct = str(content_type) ct = str(content_type)

View File

@ -19,8 +19,7 @@ def settings_to_choices(choices):
class WebApp(models.Model): class WebApp(models.Model):
""" Represents a web application """ """ Represents a web application """
name = models.CharField(_("name"), max_length=128, name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
validators=[validators.validate_name])
type = models.CharField(_("type"), max_length=32, type = models.CharField(_("type"), max_length=32,
choices=settings_to_choices(settings.WEBAPPS_TYPES), choices=settings_to_choices(settings.WEBAPPS_TYPES),
default=settings.WEBAPPS_DEFAULT_TYPE) default=settings.WEBAPPS_DEFAULT_TYPE)

View File

@ -78,7 +78,8 @@ class WebsiteOption(models.Model):
class Content(models.Model): class Content(models.Model):
webapp = models.ForeignKey('webapps.WebApp', verbose_name=_("web application")) webapp = models.ForeignKey('webapps.WebApp', verbose_name=_("web application"))
website = models.ForeignKey('websites.Website', verbose_name=_("web site")) website = models.ForeignKey('websites.Website', verbose_name=_("web site"))
path = models.CharField(_("path"), max_length=256, blank=True) path = models.CharField(_("path"), max_length=256, blank=True,
validators=[validators.validate_url_path])
class Meta: class Meta:
unique_together = ('website', 'path') unique_together = ('website', 'path')

View File

@ -74,3 +74,7 @@ def validate_password(value):
except ValueError, message: except ValueError, message:
raise ValidationError("Password %s." % str(message)[3:]) raise ValidationError("Password %s." % str(message)[3:])
def validate_url_path(value):
if not re.match(r'^\/[/.a-zA-Z0-9-]*$', value):
raise ValidationError(_('"%s" is not a valid URL path.') % value)