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 = '
%s
' % description - widget = ReadOnlyWidget(description, description) + widget = SpanWidget(display=description) self.fields['display_description'].widget = widget def clean_description(self): diff --git a/orchestra/contrib/issues/settings.py b/orchestra/contrib/issues/settings.py index 2c5ea335..6c2f55c4 100644 --- a/orchestra/contrib/issues/settings.py +++ b/orchestra/contrib/issues/settings.py @@ -1,10 +1,7 @@ from orchestra.settings import Setting -ISSUES_SUPPORT_EMAILS = Setting('ISSUES_SUPPORT_EMAILS', [ -]) +ISSUES_SUPPORT_EMAILS = Setting('ISSUES_SUPPORT_EMAILS', ()) -ISSUES_NOTIFY_SUPERUSERS = Setting('ISSUES_NOTIFY_SUPERUSERS', - True -) +ISSUES_NOTIFY_SUPERUSERS = Setting('ISSUES_NOTIFY_SUPERUSERS', True) diff --git a/orchestra/contrib/lists/backends.py b/orchestra/contrib/lists/backends.py index a506ab3d..dd9416d5 100644 --- a/orchestra/contrib/lists/backends.py +++ b/orchestra/contrib/lists/backends.py @@ -67,14 +67,15 @@ class MailmanBackend(ServiceController): context['aliases'] = self.get_virtual_aliases(context) # Preserve indentation self.append(textwrap.dedent("""\ + aliases='%(aliases)s' if [[ ! $(grep '\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then - echo '%(aliases)s' >> %(virtual_alias)s + echo "${aliases}" >> %(virtual_alias)s UPDATED_VIRTUAL_ALIAS=1 else if [[ ! $(grep '^\s*%(address_name)s@%(address_domain)s\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then sed -i -e '/^.*\s%(name)s\(%(address_regex)s\)\s*$/d' \\ -e 'N; /^\s*\\n\s*$/d; P; D' %(virtual_alias)s - echo '%(aliases)s' >> %(virtual_alias)s + echo "${aliases}" >> %(virtual_alias)s UPDATED_VIRTUAL_ALIAS=1 fi fi""") % context diff --git a/orchestra/contrib/lists/forms.py b/orchestra/contrib/lists/forms.py index 0fefbaa9..0ffff1f7 100644 --- a/orchestra/contrib/lists/forms.py +++ b/orchestra/contrib/lists/forms.py @@ -2,7 +2,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from orchestra.core.validators import validate_password -from orchestra.forms.widgets import ReadOnlyWidget +from orchestra.forms.widgets import SpanWidget class CleanAddressMixin(object): @@ -32,8 +32,8 @@ class ListCreationForm(CleanAddressMixin, forms.ModelForm): class ListChangeForm(CleanAddressMixin, forms.ModelForm): - password = forms.CharField(label=_("Password"), - widget=ReadOnlyWidget('Unknown password'), + password = forms.CharField(label=_("Password"), required=False, + widget=SpanWidget(display='Unknown password'), help_text=_("List passwords are not stored, so there is no way to see this " "list's password, but you can change the password using " "this form.")) diff --git a/orchestra/contrib/lists/settings.py b/orchestra/contrib/lists/settings.py index 4e6a015f..99119141 100644 --- a/orchestra/contrib/lists/settings.py +++ b/orchestra/contrib/lists/settings.py @@ -1,14 +1,12 @@ from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting -LISTS_DOMAIN_MODEL = Setting('LISTS_DOMAIN_MODEL', - 'domains.Domain' +LISTS_DOMAIN_MODEL = Setting('LISTS_DOMAIN_MODEL', 'domains.Domain', + validators=[Setting.validate_model_label] ) -LISTS_DEFAULT_DOMAIN = Setting('LISTS_DEFAULT_DOMAIN', - 'lists.{}'.format(ORCHESTRA_BASE_DOMAIN) -) +LISTS_DEFAULT_DOMAIN = Setting('LISTS_DEFAULT_DOMAIN', 'lists.{}'.format(ORCHESTRA_BASE_DOMAIN)) LISTS_LIST_URL = Setting('LISTS_LIST_URL', @@ -16,21 +14,13 @@ LISTS_LIST_URL = Setting('LISTS_LIST_URL', ) -LISTS_MAILMAN_POST_LOG_PATH = Setting('LISTS_MAILMAN_POST_LOG_PATH', - '/var/log/mailman/post' -) +LISTS_MAILMAN_POST_LOG_PATH = Setting('LISTS_MAILMAN_POST_LOG_PATH', '/var/log/mailman/post') -LISTS_MAILMAN_ROOT_DIR = Setting('LISTS_MAILMAN_ROOT_DIR', - '/var/lib/mailman' -) +LISTS_MAILMAN_ROOT_DIR = Setting('LISTS_MAILMAN_ROOT_DIR', '/var/lib/mailman') -LISTS_VIRTUAL_ALIAS_PATH = Setting('LISTS_VIRTUAL_ALIAS_PATH', - '/etc/postfix/mailman_virtual_aliases' -) +LISTS_VIRTUAL_ALIAS_PATH = Setting('LISTS_VIRTUAL_ALIAS_PATH', '/etc/postfix/mailman_virtual_aliases') -LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = Setting('LISTS_VIRTUAL_ALIAS_DOMAINS_PATH', - '/etc/postfix/mailman_virtual_domains' -) +LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = Setting('LISTS_VIRTUAL_ALIAS_DOMAINS_PATH', '/etc/postfix/mailman_virtual_domains') diff --git a/orchestra/contrib/mailboxes/settings.py b/orchestra/contrib/mailboxes/settings.py index 7c7a8a1c..348cd8e2 100644 --- a/orchestra/contrib/mailboxes/settings.py +++ b/orchestra/contrib/mailboxes/settings.py @@ -3,17 +3,16 @@ import textwrap from django.utils.translation import ugettext_lazy as _ +from orchestra.core.validators import validate_name from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting -MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', - 'domains.Domain' +MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', 'domains.Domain', + validators=[Setting.validate_model_label] ) -MAILBOXES_HOME = Setting('MAILBOXES_HOME', - '/home/%(name)s/' -) +MAILBOXES_HOME = Setting('MAILBOXES_HOME', '/home/%(name)s/') MAILBOXES_SIEVE_PATH = Setting('MAILBOXES_SIEVE_PATH', @@ -21,13 +20,11 @@ MAILBOXES_SIEVE_PATH = Setting('MAILBOXES_SIEVE_PATH', ) -MAILBOXES_SIEVETEST_PATH = Setting('MAILBOXES_SIEVETEST_PATH', - '/dev/shm' -) +MAILBOXES_SIEVETEST_PATH = Setting('MAILBOXES_SIEVETEST_PATH', '/dev/shm') -MAILBOXES_SIEVETEST_BIN_PATH = Setting('MAILBOXES_SIEVETEST_BIN_PATH', - '%(orchestra_root)s/bin/sieve-test' +MAILBOXES_SIEVETEST_BIN_PATH = Setting('MAILBOXES_SIEVETEST_BIN_PATH', '%(orchestra_root)s/bin/sieve-test', + validators=[Setting.string_format_validator(('orchestra_root',))] ) @@ -46,14 +43,12 @@ MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH = Setting('MAILBOXES_VIRTUAL_ALIAS_DOMAINS_ ) -MAILBOXES_LOCAL_DOMAIN = Setting('MAILBOXES_LOCAL_DOMAIN', - ORCHESTRA_BASE_DOMAIN +MAILBOXES_LOCAL_DOMAIN = Setting('MAILBOXES_LOCAL_DOMAIN', ORCHESTRA_BASE_DOMAIN, + validators=[validate_name] ) -MAILBOXES_PASSWD_PATH = Setting('MAILBOXES_PASSWD_PATH', - '/etc/dovecot/passwd' -) +MAILBOXES_PASSWD_PATH = Setting('MAILBOXES_PASSWD_PATH', '/etc/dovecot/passwd') MAILBOXES_MAILBOX_FILTERINGS = Setting('MAILBOXES_MAILBOX_FILTERINGS', { @@ -80,21 +75,15 @@ MAILBOXES_MAILBOX_DEFAULT_FILTERING = Setting('MAILBOXES_MAILBOX_DEFAULT_FILTERI ) -MAILBOXES_MAILDIRSIZE_PATH = Setting('MAILBOXES_MAILDIRSIZE_PATH', - '%(home)s/Maildir/maildirsize' +MAILBOXES_MAILDIRSIZE_PATH = Setting('MAILBOXES_MAILDIRSIZE_PATH', '%(home)s/Maildir/maildirsize') + + +MAILBOXES_LOCAL_ADDRESS_DOMAIN = Setting('MAILBOXES_LOCAL_ADDRESS_DOMAIN', ORCHESTRA_BASE_DOMAIN, + validators=[validate_name] ) -MAILBOXES_LOCAL_ADDRESS_DOMAIN = Setting('MAILBOXES_LOCAL_ADDRESS_DOMAIN', - ORCHESTRA_BASE_DOMAIN -) +MAILBOXES_MAIL_LOG_PATH = Setting('MAILBOXES_MAIL_LOG_PATH', '/var/log/mail.log') -MAILBOXES_MAIL_LOG_PATH = Setting('MAILBOXES_MAIL_LOG_PATH', - '/var/log/mail.log' -) - - -MAILBOXES_MOVE_ON_DELETE_PATH = Setting('MAILBOXES_MOVE_ON_DELETE_PATH', - '' -) +MAILBOXES_MOVE_ON_DELETE_PATH = Setting('MAILBOXES_MOVE_ON_DELETE_PATH', '') diff --git a/orchestra/contrib/orchestration/methods.py b/orchestra/contrib/orchestration/methods.py index c0340e4e..2311062e 100644 --- a/orchestra/contrib/orchestration/methods.py +++ b/orchestra/contrib/orchestration/methods.py @@ -31,7 +31,7 @@ def SSH(backend, log, server, cmds, async=False): script = script.replace('\r', '') bscript = script.encode('utf-8') digest = hashlib.md5(bscript).hexdigest() - path = os.path.join(settings.ORCHESTRATION_TEMP_SCRIPT_PATH, digest) + path = os.path.join(settings.ORCHESTRATION_TEMP_SCRIPT_DIR, digest) remote_path = "%s.remote" % path log.script = '# %s\n%s' % (remote_path, script) log.save(update_fields=['script']) diff --git a/orchestra/contrib/orchestration/middlewares.py b/orchestra/contrib/orchestration/middlewares.py index 156d931f..95d68725 100644 --- a/orchestra/contrib/orchestration/middlewares.py +++ b/orchestra/contrib/orchestration/middlewares.py @@ -94,7 +94,7 @@ class OperationsMiddleware(object): def process_response(self, request, response): """ Processes pending backend operations """ if not isinstance(response, HttpResponseServerError): - operations = type(self).get_pending_operations() + operations = self.get_pending_operations() if operations: try: scripts, block = manager.generate(operations) diff --git a/orchestra/contrib/orchestration/settings.py b/orchestra/contrib/orchestration/settings.py index 9e963889..df5a482e 100644 --- a/orchestra/contrib/orchestration/settings.py +++ b/orchestra/contrib/orchestration/settings.py @@ -5,8 +5,10 @@ from orchestra.settings import Setting ORCHESTRATION_OS_CHOICES = Setting('ORCHESTRATION_OS_CHOICES', ( - ('LINUX', "Linux"), -)) + ('LINUX', "Linux"), + ), + validators=[Setting.validate_choices] +) ORCHESTRATION_DEFAULT_OS = Setting('ORCHESTRATION_DEFAULT_OS', 'LINUX', @@ -17,19 +19,15 @@ ORCHESTRATION_SSH_KEY_PATH = Setting('ORCHESTRATION_SSH_KEY_PATH', path.join(path.expanduser('~'), '.ssh/id_rsa')) -ORCHESTRATION_ROUTER = Setting('ORCHESTRATION_ROUTER', - 'orchestra.contrib.orchestration.models.Route' +ORCHESTRATION_ROUTER = Setting('ORCHESTRATION_ROUTER', 'orchestra.contrib.orchestration.models.Route', + validators=[Setting.validate_import_class] ) -ORCHESTRATION_TEMP_SCRIPT_PATH = Setting('ORCHESTRATION_TEMP_SCRIPT_PATH', - '/dev/shm' -) +ORCHESTRATION_TEMP_SCRIPT_DIR = Setting('ORCHESTRATION_TEMP_SCRIPT_DIR', '/dev/shm') -ORCHESTRATION_DISABLE_EXECUTION = Setting('ORCHESTRATION_DISABLE_EXECUTION', - False -) +ORCHESTRATION_DISABLE_EXECUTION = Setting('ORCHESTRATION_DISABLE_EXECUTION', False) ORCHESTRATION_BACKEND_CLEANUP_DELTA = Setting('ORCHESTRATION_BACKEND_CLEANUP_DELTA', diff --git a/orchestra/contrib/orders/actions.py b/orchestra/contrib/orders/actions.py index f8b5e8a0..4e1023da 100644 --- a/orchestra/contrib/orders/actions.py +++ b/orchestra/contrib/orders/actions.py @@ -91,7 +91,6 @@ class BillSelectedOrders(object): url = reverse('admin:bills_bill_changelist') ids = ','.join(map(str, bills)) url += '?id__in=%s' % ids - num = len(bills) msg = ungettext( 'One bill has been created.', '{num} bills have been created.', @@ -100,11 +99,18 @@ class BillSelectedOrders(object): self.modeladmin.message_user(request, msg, messages.INFO) return bills = self.queryset.bill(commit=False, **self.options) + bills_with_total = [] + for account, lines in bills: + total = 0 + for line in lines: + discount = sum([discount.total for discount in line.discounts]) + total += line.subtotal + discount + bills_with_total.append((account, total, lines)) self.context.update({ 'title': _("Confirmation for billing selected orders"), 'step': 3, 'form': form, - 'bills': bills, + 'bills': bills_with_total, }) return render(request, self.template, self.context) diff --git a/orchestra/contrib/orders/settings.py b/orchestra/contrib/orders/settings.py index ea7f56fe..fad39cab 100644 --- a/orchestra/contrib/orders/settings.py +++ b/orchestra/contrib/orders/settings.py @@ -1,34 +1,34 @@ from orchestra.settings import Setting -# Pluggable backend for bill generation. -ORDERS_BILLING_BACKEND = Setting('ORDERS_BILLING_BACKEND', - 'orchestra.contrib.orders.billing.BillsBackend' +ORDERS_BILLING_BACKEND = Setting('ORDERS_BILLING_BACKEND', 'orchestra.contrib.orders.billing.BillsBackend', + validators=[Setting.validate_import_class], + help_text="Pluggable backend for bill generation.", ) -# Pluggable service class -ORDERS_SERVICE_MODEL = Setting('ORDERS_SERVICE_MODEL', - 'services.Service' +ORDERS_SERVICE_MODEL = Setting('ORDERS_SERVICE_MODEL', 'services.Service', + validators=[Setting.validate_model_label], + help_text="Pluggable service class." ) -# Prevent inspecting these apps for service accounting ORDERS_EXCLUDED_APPS = Setting('ORDERS_EXCLUDED_APPS', ( - 'orders', - 'admin', - 'contenttypes', - 'auth', - 'migrations', - 'sessions', - 'orchestration', - 'bills', - 'services', -)) - - -# Only account for significative changes -# metric_storage new value: lastvalue*(1+threshold) > currentvalue or lastvalue*threshold < currentvalue -ORDERS_METRIC_ERROR = Setting('ORDERS_METRIC_ERROR', - 0.01 + 'orders', + 'admin', + 'contenttypes', + 'auth', + 'migrations', + 'sessions', + 'orchestration', + 'bills', + 'services', + ), + help_text="Prevent inspecting these apps for service accounting." +) + + +ORDERS_METRIC_ERROR = Setting('ORDERS_METRIC_ERROR', 0.01, + help_text=("Only account for significative changes.
" + "metric_storage new value: lastvalue*(1+threshold) > currentvalue or lastvalue*threshold < currentvalue.") ) diff --git a/orchestra/contrib/orders/templates/admin/orders/order/bill_selected_options.html b/orchestra/contrib/orders/templates/admin/orders/order/bill_selected_options.html index 4fa34595..b27b2594 100644 --- a/orchestra/contrib/orders/templates/admin/orders/order/bill_selected_options.html +++ b/orchestra/contrib/orders/templates/admin/orders/order/bill_selected_options.html @@ -28,11 +28,11 @@
{% if bills %} - {% for account, lines in bills %} + {% for account, total, lines in bills %}