Added clean methods stripping withespaces
This commit is contained in:
parent
147c1d0dd6
commit
5237a4130f
3
TODO.md
3
TODO.md
|
@ -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 ?
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
|
@ -48,6 +48,15 @@ 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)
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,24 @@ class SEPADirectDebitForm(PluginDataForm):
|
||||||
widget=forms.TextInput(attrs={'size': '50'}))
|
widget=forms.TextInput(attrs={'size': '50'}))
|
||||||
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):
|
||||||
|
|
|
@ -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__
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"),
|
||||||
|
@ -113,6 +112,9 @@ class Resource(models.Model):
|
||||||
task='resources.Monitor',
|
task='resources.Monitor',
|
||||||
args=[self.pk]
|
args=[self.pk]
|
||||||
).delete()
|
).delete()
|
||||||
|
|
||||||
|
def get_scale(self):
|
||||||
|
return eval(self.scale)
|
||||||
|
|
||||||
|
|
||||||
class ResourceData(models.Model):
|
class ResourceData(models.Model):
|
||||||
|
|
|
@ -27,6 +27,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):
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue