diff --git a/TODO.md b/TODO.md
index f72179e1..16c850ae 100644
--- a/TODO.md
+++ b/TODO.md
@@ -280,17 +280,15 @@ https://code.djangoproject.com/ticket/24576
# bill.totals make it 100% computed?
* joomla: wget https://github.com/joomla/joomla-cms/releases/download/3.4.1/Joomla_3.4.1-Stable-Full_Package.tar.gz -O - | tar xvfz -
-# replace multichoicefield and jsonfield by ArrayField, HStoreField
+
+# bill confirmation: show total
# Amend lines???
# Determine the difference between data serializer used for validation and used for the rest API!
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support
-# @classmethods do not need to be called with type(object)!
-
-# Deprectae widgets.showtext and readonlyField by ReadOnlyFormMixin
-
# custom validation for settings
# TODO orchestra related services code reload: celery/uwsgi reloading find aonther way without root and implement reload
# insert settings on dashboard dynamically
+# convert all complex settings to string
diff --git a/orchestra/admin/forms.py b/orchestra/admin/forms.py
index b453c9f0..f83acd7c 100644
--- a/orchestra/admin/forms.py
+++ b/orchestra/admin/forms.py
@@ -7,7 +7,7 @@ from django.forms.models import modelformset_factory, BaseModelFormSet
from django.template import Template, Context
from django.utils.translation import ugettext_lazy as _
-from orchestra.forms.widgets import ShowTextWidget, ReadOnlyWidget
+from orchestra.forms.widgets import SpanWidget
from ..core.validators import validate_password
@@ -71,10 +71,10 @@ class AdminPasswordChangeForm(forms.Form):
self.user = user
super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
for ix, rel in enumerate(self.related):
- self.fields['password1_%i' % ix] = forms.CharField(
- label=_("Password"), widget=forms.PasswordInput, required=False)
- self.fields['password2_%i' % ix] = forms.CharField(
- label=_("Password (again)"), widget=forms.PasswordInput, required=False)
+ self.fields['password1_%i' % ix] = forms.CharField(label=_("Password"),
+ widget=forms.PasswordInput, required=False)
+ self.fields['password2_%i' % ix] = forms.CharField(label=_("Password (again)"),
+ widget=forms.PasswordInput, required=False)
setattr(self, 'clean_password2_%i' % ix, partial(self.clean_password2, ix=ix))
def clean_password2(self, ix=''):
@@ -138,21 +138,20 @@ class AdminPasswordChangeForm(forms.Form):
class SendEmailForm(forms.Form):
email_from = forms.EmailField(label=_("From"),
- widget=forms.TextInput(attrs={'size': '118'}))
- to = forms.CharField(label="To", required=False,
- widget=ShowTextWidget())
+ widget=forms.TextInput(attrs={'size': '118'}))
+ to = forms.CharField(label="To", required=False)
extra_to = forms.CharField(label="To (extra)", required=False,
- widget=forms.TextInput(attrs={'size': '118'}))
+ widget=forms.TextInput(attrs={'size': '118'}))
subject = forms.CharField(label=_("Subject"),
- widget=forms.TextInput(attrs={'size': '118'}))
+ widget=forms.TextInput(attrs={'size': '118'}))
message = forms.CharField(label=_("Message"),
- widget=forms.Textarea(attrs={'cols': 118, 'rows': 15}))
+ widget=forms.Textarea(attrs={'cols': 118, 'rows': 15}))
def __init__(self, *args, **kwargs):
super(SendEmailForm, self).__init__(*args, **kwargs)
initial = kwargs.get('initial')
if 'to' in initial:
- self.fields['to'].widget = ReadOnlyWidget(initial['to'])
+ self.fields['to'].widget = SpanWidget(original=initial['to'])
else:
self.fields.pop('to')
diff --git a/orchestra/contrib/accounts/settings.py b/orchestra/contrib/accounts/settings.py
index 81ab8ac8..644c4259 100644
--- a/orchestra/contrib/accounts/settings.py
+++ b/orchestra/contrib/accounts/settings.py
@@ -5,29 +5,33 @@ from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
ACCOUNTS_TYPES = Setting('ACCOUNTS_TYPES', (
- ('INDIVIDUAL', _("Individual")),
- ('ASSOCIATION', _("Association")),
- ('CUSTOMER', _("Customer")),
- ('COMPANY', _("Company")),
- ('PUBLICBODY', _("Public body")),
- ('STAFF', _("Staff")),
- ('FRIEND', _("Friend")),
-))
+ ('INDIVIDUAL', _("Individual")),
+ ('ASSOCIATION', _("Association")),
+ ('CUSTOMER', _("Customer")),
+ ('COMPANY', _("Company")),
+ ('PUBLICBODY', _("Public body")),
+ ('STAFF', _("Staff")),
+ ('FRIEND', _("Friend")),
+ ),
+ validators=[Setting.validate_choices]
+)
ACCOUNTS_DEFAULT_TYPE = Setting('ACCOUNTS_DEFAULT_TYPE', 'INDIVIDUAL', choices=ACCOUNTS_TYPES)
ACCOUNTS_LANGUAGES = Setting('ACCOUNTS_LANGUAGES', (
- ('EN', _('English')),
-))
+ ('EN', _('English')),
+ ),
+ validators=[Setting.validate_choices]
+)
ACCOUNTS_DEFAULT_LANGUAGE = Setting('ACCOUNTS_DEFAULT_LANGUAGE', 'EN', choices=ACCOUNTS_LANGUAGES)
-ACCOUNTS_SYSTEMUSER_MODEL = Setting('ACCOUNTS_SYSTEMUSER_MODEL',
- 'systemusers.SystemUser'
+ACCOUNTS_SYSTEMUSER_MODEL = Setting('ACCOUNTS_SYSTEMUSER_MODEL', 'systemusers.SystemUser',
+ validators=[Setting.validate_model_label],
)
diff --git a/orchestra/contrib/bills/actions.py b/orchestra/contrib/bills/actions.py
index ef85f59c..ce638b5a 100644
--- a/orchestra/contrib/bills/actions.py
+++ b/orchestra/contrib/bills/actions.py
@@ -56,7 +56,7 @@ def close_bills(modeladmin, request, queryset):
for bill in queryset:
if not validate_contact(request, bill):
return
- SelectSourceFormSet = adminmodelformset_factory(SelectSourceForm, modeladmin, extra=0)
+ SelectSourceFormSet = adminmodelformset_factory(modeladmin, SelectSourceForm, extra=0)
formset = SelectSourceFormSet(queryset=queryset)
if request.POST.get('post') == 'generic_confirmation':
formset = SelectSourceFormSet(request.POST, request.FILES, queryset=queryset)
diff --git a/orchestra/contrib/bills/forms.py b/orchestra/contrib/bills/forms.py
index 955fb8f8..d6236fa1 100644
--- a/orchestra/contrib/bills/forms.py
+++ b/orchestra/contrib/bills/forms.py
@@ -2,37 +2,38 @@ from django import forms
from django.utils.translation import ugettext_lazy as _
from orchestra.admin.utils import admin_link
-from orchestra.forms.widgets import ShowTextWidget
+from orchestra.forms import SpanWidget
class SelectSourceForm(forms.ModelForm):
- bill_link = forms.CharField(label=_("Number"), required=False, widget=ShowTextWidget())
+ bill_link = forms.CharField(label=_("Number"), required=False, widget=SpanWidget)
account_link = forms.CharField(label=_("Account"), required=False)
- display_total = forms.CharField(label=_("Total"), required=False)
- display_type = forms.CharField(label=_("Type"), required=False, widget=ShowTextWidget())
+ show_total = forms.CharField(label=_("Total"), required=False, widget=SpanWidget)
+ display_type = forms.CharField(label=_("Type"), required=False, widget=SpanWidget)
source = forms.ChoiceField(label=_("Source"), required=False)
class Meta:
fields = (
- 'bill_link', 'display_type', 'account_link', 'display_total',
- 'source'
+ 'bill_link', 'display_type', 'account_link', 'show_total', 'source'
)
- readonly_fields = ('account_link', 'display_total')
+ readonly_fields = ('account_link',)
def __init__(self, *args, **kwargs):
super(SelectSourceForm, self).__init__(*args, **kwargs)
bill = kwargs.get('instance')
if bill:
+ total = bill.get_total()
sources = bill.account.paymentsources.filter(is_active=True)
- recharge = bool(bill.total < 0)
+ recharge = bool(total < 0)
choices = [(None, '-----------')]
for source in sources:
if not recharge or source.method_class().allow_recharge:
choices.append((source.pk, str(source)))
self.fields['source'].choices = choices
self.fields['source'].initial = choices[-1][0]
- self.fields['bill_link'].initial = admin_link('__str__')(bill)
- self.fields['display_type'].initial = bill.get_type_display()
+ self.fields['show_total'].widget.display = total
+ self.fields['bill_link'].widget.display = admin_link('__str__')(bill)
+ self.fields['display_type'].widget.display = bill.get_type_display()
def clean_source(self):
source_id = self.cleaned_data['source']
diff --git a/orchestra/contrib/bills/settings.py b/orchestra/contrib/bills/settings.py
index b80d606e..4b2e4739 100644
--- a/orchestra/contrib/bills/settings.py
+++ b/orchestra/contrib/bills/settings.py
@@ -7,69 +7,43 @@ from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
BILLS_NUMBER_LENGTH = Setting('BILLS_NUMBER_LENGTH', 4)
-BILLS_INVOICE_NUMBER_PREFIX = Setting('BILLS_INVOICE_NUMBER_PREFIX',
- 'I'
-)
+BILLS_INVOICE_NUMBER_PREFIX = Setting('BILLS_INVOICE_NUMBER_PREFIX', 'I')
-BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX',
- 'A'
-)
+BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_INVOICE_NUMBER_PREFIX', 'A')
-BILLS_FEE_NUMBER_PREFIX = Setting('BILLS_FEE_NUMBER_PREFIX',
- 'F'
-)
+BILLS_FEE_NUMBER_PREFIX = Setting('BILLS_FEE_NUMBER_PREFIX', 'F')
-BILLS_AMENDMENT_FEE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_FEE_NUMBER_PREFIX',
- 'B'
-)
+BILLS_AMENDMENT_FEE_NUMBER_PREFIX = Setting('BILLS_AMENDMENT_FEE_NUMBER_PREFIX', 'B')
-BILLS_PROFORMA_NUMBER_PREFIX = Setting('BILLS_PROFORMA_NUMBER_PREFIX',
- 'P'
-)
+BILLS_PROFORMA_NUMBER_PREFIX = Setting('BILLS_PROFORMA_NUMBER_PREFIX', 'P')
-BILLS_DEFAULT_TEMPLATE = Setting('BILLS_DEFAULT_TEMPLATE',
- 'bills/microspective.html'
-)
+BILLS_DEFAULT_TEMPLATE = Setting('BILLS_DEFAULT_TEMPLATE', 'bills/microspective.html')
-BILLS_FEE_TEMPLATE = Setting('BILLS_FEE_TEMPLATE',
- 'bills/microspective-fee.html'
-)
+BILLS_FEE_TEMPLATE = Setting('BILLS_FEE_TEMPLATE', 'bills/microspective-fee.html')
-BILLS_PROFORMA_TEMPLATE = Setting('BILLS_PROFORMA_TEMPLATE',
- 'bills/microspective-proforma.html'
-)
+BILLS_PROFORMA_TEMPLATE = Setting('BILLS_PROFORMA_TEMPLATE', 'bills/microspective-proforma.html')
-BILLS_CURRENCY = Setting('BILLS_CURRENCY',
- 'euro'
-)
+BILLS_CURRENCY = Setting('BILLS_CURRENCY', 'euro')
-BILLS_SELLER_PHONE = Setting('BILLS_SELLER_PHONE',
- '111-112-11-222'
-)
+BILLS_SELLER_PHONE = Setting('BILLS_SELLER_PHONE', '111-112-11-222')
-BILLS_SELLER_EMAIL = Setting('BILLS_SELLER_EMAIL',
- 'sales@{}'.format(ORCHESTRA_BASE_DOMAIN)
-)
+BILLS_SELLER_EMAIL = Setting('BILLS_SELLER_EMAIL', 'sales@{}'.format(ORCHESTRA_BASE_DOMAIN))
-BILLS_SELLER_WEBSITE = Setting('BILLS_SELLER_WEBSITE',
- 'www.{}'.format(ORCHESTRA_BASE_DOMAIN)
-)
+BILLS_SELLER_WEBSITE = Setting('BILLS_SELLER_WEBSITE', 'www.{}'.format(ORCHESTRA_BASE_DOMAIN))
-BILLS_SELLER_BANK_ACCOUNT = Setting('BILLS_SELLER_BANK_ACCOUNT',
- '0000 0000 00 00000000 (Orchestra Bank)'
-)
+BILLS_SELLER_BANK_ACCOUNT = Setting('BILLS_SELLER_BANK_ACCOUNT', '0000 0000 00 00000000 (Orchestra Bank)')
BILLS_EMAIL_NOTIFICATION_TEMPLATE = Setting('BILLS_EMAIL_NOTIFICATION_TEMPLATE',
@@ -77,18 +51,16 @@ BILLS_EMAIL_NOTIFICATION_TEMPLATE = Setting('BILLS_EMAIL_NOTIFICATION_TEMPLATE',
)
-BILLS_ORDER_MODEL = Setting('BILLS_ORDER_MODEL',
- 'orders.Order'
+BILLS_ORDER_MODEL = Setting('BILLS_ORDER_MODEL', 'orders.Order',
+ validators=[Setting.validate_model_label]
)
-BILLS_CONTACT_DEFAULT_CITY = Setting('BILLS_CONTACT_DEFAULT_CITY',
- 'Barcelona'
-)
+BILLS_CONTACT_DEFAULT_CITY = Setting('BILLS_CONTACT_DEFAULT_CITY', 'Barcelona')
BILLS_CONTACT_COUNTRIES = Setting('BILLS_CONTACT_COUNTRIES', tuple((k,v) for k,v in data.COUNTRIES.items()),
- editable=False
+ serializable=False
)
diff --git a/orchestra/contrib/contacts/settings.py b/orchestra/contrib/contacts/settings.py
index 8f6fb6a3..64745f0d 100644
--- a/orchestra/contrib/contacts/settings.py
+++ b/orchestra/contrib/contacts/settings.py
@@ -1,26 +1,32 @@
-from django.conf import settings
from django_countries import data
from orchestra.settings import Setting
-CONTACTS_DEFAULT_EMAIL_USAGES = Setting('CONTACTS_DEFAULT_EMAIL_USAGES', (
- 'SUPPORT',
- 'ADMIN',
- 'BILLING',
- 'TECH',
- 'ADDS',
- 'EMERGENCY'
-))
-
-
-CONTACTS_DEFAULT_CITY = Setting('CONTACTS_DEFAULT_CITY',
- 'Barcelona'
+CONTACTS_DEFAULT_EMAIL_USAGES = Setting('CONTACTS_DEFAULT_EMAIL_USAGES',
+ default=(
+ 'SUPPORT',
+ 'ADMIN',
+ 'BILLING',
+ 'TECH',
+ 'ADDS',
+ 'EMERGENCY'
+ ),
)
-CONTACTS_COUNTRIES = Setting('CONTACTS_COUNTRIES', tuple((k,v) for k,v in data.COUNTRIES.items()),
- editable=False)
+CONTACTS_DEFAULT_CITY = Setting('CONTACTS_DEFAULT_CITY',
+ default='Barcelona'
+)
-CONTACTS_DEFAULT_COUNTRY = Setting('CONTACTS_DEFAULT_COUNTRY', 'ES', choices=CONTACTS_COUNTRIES)
+CONTACTS_COUNTRIES = Setting('CONTACTS_COUNTRIES',
+ default=tuple((k,v) for k,v in data.COUNTRIES.items()),
+ serializable=False
+)
+
+
+CONTACTS_DEFAULT_COUNTRY = Setting('CONTACTS_DEFAULT_COUNTRY',
+ default='ES',
+ choices=CONTACTS_COUNTRIES
+)
diff --git a/orchestra/contrib/databases/settings.py b/orchestra/contrib/databases/settings.py
index 3b4d0d2d..4797680d 100644
--- a/orchestra/contrib/databases/settings.py
+++ b/orchestra/contrib/databases/settings.py
@@ -1,17 +1,15 @@
-from django.conf import settings
-
from orchestra.settings import Setting
DATABASES_TYPE_CHOICES = Setting('DATABASES_TYPE_CHOICES', (
- ('mysql', 'MySQL'),
- ('postgres', 'PostgreSQL'),
-))
+ ('mysql', 'MySQL'),
+ ('postgres', 'PostgreSQL'),
+ ),
+ validators=[Setting.validate_choices]
+)
DATABASES_DEFAULT_TYPE = Setting('DATABASES_DEFAULT_TYPE', 'mysql', choices=DATABASES_TYPE_CHOICES)
-DATABASES_DEFAULT_HOST = Setting('DATABASES_DEFAULT_HOST',
- 'localhost'
-)
+DATABASES_DEFAULT_HOST = Setting('DATABASES_DEFAULT_HOST', 'localhost')
diff --git a/orchestra/contrib/domains/models.py b/orchestra/contrib/domains/models.py
index 213aa9f2..4fac16bf 100644
--- a/orchestra/contrib/domains/models.py
+++ b/orchestra/contrib/domains/models.py
@@ -94,7 +94,7 @@ class Domain(models.Model):
return self.origin.subdomain_set.all().prefetch_related('records')
def get_parent(self, top=False):
- return type(self).get_parent_domain(self.name, top=top)
+ return self.get_parent_domain(self.name, top=top)
def render_zone(self):
origin = self.origin
diff --git a/orchestra/contrib/domains/settings.py b/orchestra/contrib/domains/settings.py
index 2c20a7b9..6712d415 100644
--- a/orchestra/contrib/domains/settings.py
+++ b/orchestra/contrib/domains/settings.py
@@ -1,5 +1,4 @@
-from django.conf import settings
-
+from orchestra.core.validators import validate_ipv4_address, validate_ipv6_address
from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
@@ -58,18 +57,19 @@ DOMAINS_CHECKZONE_BIN_PATH = Setting('DOMAINS_CHECKZONE_BIN_PATH',
)
-DOMAINS_ZONE_VALIDATION_TMP_DIR = Setting('DOMAINS_ZONE_VALIDATION_TMP_DIR', '/dev/shm',
+DOMAINS_ZONE_VALIDATION_TMP_DIR = Setting('DOMAINS_ZONE_VALIDATION_TMP_DIR',
+ '/dev/shm',
help_text="Used for creating temporary zone files used for validation."
)
-DOMAINS_DEFAULT_A = Setting('DOMAINS_DEFAULT_A',
- '10.0.3.13'
+DOMAINS_DEFAULT_A = Setting('DOMAINS_DEFAULT_A', '10.0.3.13',
+ validators=[validate_ipv4_address]
)
-DOMAINS_DEFAULT_AAAA = Setting('DOMAINS_DEFAULT_AAAA',
- ''
+DOMAINS_DEFAULT_AAAA = Setting('DOMAINS_DEFAULT_AAAA', '',
+ validators=[validate_ipv6_address]
)
@@ -96,11 +96,13 @@ DOMAINS_FORBIDDEN = Setting('DOMAINS_FORBIDDEN', '',
)
-DOMAINS_MASTERS = Setting('DOMAINS_MASTERS', (),
+DOMAINS_MASTERS = Setting('DOMAINS_MASTERS',
+ (),
help_text="Additional master server ip addresses other than autodiscovered by router.get_servers()."
)
-DOMAINS_SLAVES = Setting('DOMAINS_SLAVES', (),
+DOMAINS_SLAVES = Setting('DOMAINS_SLAVES',
+ (),
help_text="Additional slave server ip addresses other than autodiscovered by router.get_servers()."
)
diff --git a/orchestra/contrib/issues/forms.py b/orchestra/contrib/issues/forms.py
index 01b1b6a8..334187b4 100644
--- a/orchestra/contrib/issues/forms.py
+++ b/orchestra/contrib/issues/forms.py
@@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from markdown import markdown
-from orchestra.forms.widgets import ReadOnlyWidget
+from orchestra.forms.widgets import SpanWidget
from .models import Queue, Ticket
@@ -40,7 +40,7 @@ class MessageInlineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MessageInlineForm, self).__init__(*args, **kwargs)
- self.fields['created_on'].widget = ReadOnlyWidget('')
+ self.fields['created_on'].widget = SpanWidget(display='')
def clean_content(self):
""" clean HTML tags """
@@ -98,7 +98,7 @@ class TicketForm(forms.ModelForm):
description = description.replace('\n', '
')
description = description.replace('#Ha9G9-?8', '>\n')
description = '