Random fixes
This commit is contained in:
parent
d0c7c760af
commit
c4e8c07311
3
TODO.md
3
TODO.md
|
@ -160,3 +160,6 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
* prevent adding local email addresses on account.contacts account.email
|
||||
|
||||
* Resource monitoring without ROUTE alert or explicit error
|
||||
|
||||
|
||||
* Domain validation has to be done with injected records and subdomains
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.utils.timezone
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('systemusers', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Account',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
|
||||
('username', models.CharField(help_text='Required. 30 characters or fewer. Letters, digits and ./-/_ only.', unique=True, max_length=64, verbose_name='username', validators=[django.core.validators.RegexValidator(b'^[\\w.-]+$', 'Enter a valid username.', b'invalid')])),
|
||||
('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
|
||||
('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
|
||||
('email', models.EmailField(help_text='Used for password recovery', max_length=75, verbose_name='email address')),
|
||||
('type', models.CharField(default=b'INDIVIDUAL', max_length=32, verbose_name='type', choices=[(b'INDIVIDUAL', 'Individual'), (b'ASSOCIATION', 'Association'), (b'CUSTOMER', 'Customer'), (b'STAFF', 'Staff')])),
|
||||
('language', models.CharField(default=b'ca', max_length=2, verbose_name='language', choices=[(b'ca', 'Catalan'), (b'es', 'Spanish'), (b'en', 'English')])),
|
||||
('comments', models.TextField(max_length=256, verbose_name='comments', blank=True)),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this account should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('main_systemuser', models.ForeignKey(related_name='accounts_main', to='systemusers.SystemUser', null=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -1,34 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='first_name',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='last_name',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='full_name',
|
||||
field=models.CharField(default='', max_length=30, verbose_name='full name'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='account',
|
||||
name='short_name',
|
||||
field=models.CharField(default='', max_length=30, verbose_name='short name', blank=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -14,13 +14,13 @@ from . import settings
|
|||
|
||||
class Account(auth.AbstractBaseUser):
|
||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
|
||||
help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."),
|
||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||
_("Enter a valid username."), 'invalid')])
|
||||
main_systemuser = models.ForeignKey(settings.ACCOUNTS_SYSTEMUSER_MODEL, null=True,
|
||||
related_name='accounts_main')
|
||||
short_name = models.CharField(_("short name"), max_length=30, blank=True)
|
||||
full_name = models.CharField(_("full name"), max_length=30)
|
||||
related_name='accounts_main', editable=False)
|
||||
short_name = models.CharField(_("short name"), max_length=64, blank=True)
|
||||
full_name = models.CharField(_("full name"), max_length=256)
|
||||
email = models.EmailField(_('email address'), help_text=_("Used for password recovery"))
|
||||
type = models.CharField(_("type"), choices=settings.ACCOUNTS_TYPES,
|
||||
max_length=32, default=settings.ACCOUNTS_DEFAULT_TYPE)
|
||||
|
|
|
@ -15,7 +15,7 @@ ACCOUNTS_DEFAULT_TYPE = getattr(settings, 'ACCOUNTS_DEFAULT_TYPE', 'INDIVIDUAL')
|
|||
|
||||
|
||||
ACCOUNTS_LANGUAGES = getattr(settings, 'ACCOUNTS_LANGUAGES', (
|
||||
('en', _('English')),
|
||||
('EN', _('English')),
|
||||
))
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ ACCOUNTS_SYSTEMUSER_MODEL = getattr(settings, 'ACCOUNTS_SYSTEMUSER_MODEL',
|
|||
'systemusers.SystemUser')
|
||||
|
||||
|
||||
ACCOUNTS_DEFAULT_LANGUAGE = getattr(settings, 'ACCOUNTS_DEFAULT_LANGUAGE', 'en')
|
||||
ACCOUNTS_DEFAULT_LANGUAGE = getattr(settings, 'ACCOUNTS_DEFAULT_LANGUAGE', 'EN')
|
||||
|
||||
|
||||
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK', 1)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from django.core.validators import ValidationError
|
||||
from django.core.validators import ValidationError, RegexValidator
|
||||
from django.db import models
|
||||
from django.template import loader, Context
|
||||
from django.utils import timezone
|
||||
|
@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from orchestra.apps.accounts.models import Account
|
||||
from orchestra.apps.contacts.models import Contact
|
||||
from orchestra.core import accounts
|
||||
from orchestra.core import accounts, validators
|
||||
from orchestra.utils.html import html_to_pdf
|
||||
|
||||
from . import settings
|
||||
|
@ -24,8 +24,11 @@ class BillContact(models.Model):
|
|||
address = models.TextField(_("address"))
|
||||
city = models.CharField(_("city"), max_length=128,
|
||||
default=settings.BILLS_CONTACT_DEFAULT_CITY)
|
||||
zipcode = models.PositiveIntegerField(_("zip code"))
|
||||
zipcode = models.CharField(_("zip code"), max_length=10,
|
||||
validators=[RegexValidator(r'^[0-9A-Z]{3,10}$',
|
||||
_("Enter a valid zipcode."), 'invalid')])
|
||||
country = models.CharField(_("country"), max_length=20,
|
||||
choices=settings.BILLS_CONTACT_COUNTRIES,
|
||||
default=settings.BILLS_CONTACT_DEFAULT_COUNTRY)
|
||||
vat = models.CharField(_("VAT number"), max_length=64)
|
||||
|
||||
|
@ -34,6 +37,12 @@ class BillContact(models.Model):
|
|||
|
||||
def get_name(self):
|
||||
return self.name or self.account.get_full_name()
|
||||
|
||||
def clean(self):
|
||||
self.vat = self.vat.strip()
|
||||
self.city = self.city.strip()
|
||||
validators.validate_vat(self.vat, self.country)
|
||||
validators.validate_zipcode(self.zipcode, self.country)
|
||||
|
||||
|
||||
class BillManager(models.Manager):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf import settings
|
||||
from django_countries import data
|
||||
|
||||
|
||||
BILLS_NUMBER_LENGTH = getattr(settings, 'BILLS_NUMBER_LENGTH', 4)
|
||||
|
@ -57,4 +58,9 @@ BILLS_ORDER_MODEL = getattr(settings, 'BILLS_ORDER_MODEL', 'orders.Order')
|
|||
BILLS_CONTACT_DEFAULT_CITY = getattr(settings, 'BILLS_CONTACT_DEFAULT_CITY', 'Barcelona')
|
||||
|
||||
|
||||
BILLS_CONTACT_DEFAULT_COUNTRY = getattr(settings, 'BILLS_CONTACT_DEFAULT_COUNTRY', 'Spain')
|
||||
BILLS_CONTACT_COUNTRIES = getattr(settings, 'BILLS_CONTACT_COUNTRIES', data.COUNTRIES)
|
||||
|
||||
|
||||
BILLS_CONTACT_DEFAULT_COUNTRY = getattr(settings, 'BILLS_CONTACT_DEFAULT_COUNTRY', 'ES')
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.core import accounts
|
||||
from orchestra.core import accounts, validators
|
||||
from orchestra.models.fields import MultiSelectField
|
||||
|
||||
from . import settings
|
||||
|
||||
|
||||
validate_phone = lambda p: validators.validate_phone(p, settings.CONTACTS_DEFAULT_COUNTRY)
|
||||
|
||||
|
||||
class ContactQuerySet(models.QuerySet):
|
||||
def filter(self, *args, **kwargs):
|
||||
usages = kwargs.pop('email_usages', [])
|
||||
|
@ -37,14 +42,17 @@ class Contact(models.Model):
|
|||
email_usage = MultiSelectField(_("email usage"), max_length=256, blank=True,
|
||||
choices=EMAIL_USAGES,
|
||||
default=settings.CONTACTS_DEFAULT_EMAIL_USAGES)
|
||||
phone = models.CharField(_("phone"), max_length=32, blank=True)
|
||||
phone2 = models.CharField(_("alternative phone"), max_length=32, blank=True)
|
||||
phone = models.CharField(_("phone"), max_length=32, blank=True,
|
||||
validators=[validate_phone])
|
||||
phone2 = models.CharField(_("alternative phone"), max_length=32, blank=True,
|
||||
validators=[validate_phone])
|
||||
address = models.TextField(_("address"), blank=True)
|
||||
city = models.CharField(_("city"), max_length=128, blank=True,
|
||||
default=settings.CONTACTS_DEFAULT_CITY)
|
||||
zipcode = models.PositiveIntegerField(_("zip code"), null=True, blank=True)
|
||||
city = models.CharField(_("city"), max_length=128, blank=True)
|
||||
zipcode = models.CharField(_("zip code"), max_length=10, blank=True,
|
||||
validators=[RegexValidator(r'^[0-9,A-Z]{3,10}$',
|
||||
_("Enter a valid zipcode."), 'invalid')])
|
||||
country = models.CharField(_("country"), max_length=20, blank=True,
|
||||
default=settings.CONTACTS_DEFAULT_COUNTRY)
|
||||
choices=settings.CONTACTS_COUNTRIES)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.short_name
|
||||
|
@ -57,6 +65,12 @@ class Contact(models.Model):
|
|||
self.address = self.address.strip()
|
||||
self.city = self.city.strip()
|
||||
self.country = self.country.strip()
|
||||
if self.address and not (self.city and self.zipcode and self.country):
|
||||
raise ValidationError(_("City, zipcode and country must be provided when address is provided."))
|
||||
if self.zipcode and not self.country:
|
||||
raise ValidationError(_("Country must be provided when zipcode is provided."))
|
||||
elif self.zipcode and self.country:
|
||||
validators.validate_zipcode(self.zipcode, self.country)
|
||||
|
||||
|
||||
accounts.register(Contact)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf import settings
|
||||
from django_countries import data
|
||||
|
||||
|
||||
CONTACTS_DEFAULT_EMAIL_USAGES = getattr(settings, 'CONTACTS_DEFAULT_EMAIL_USAGES',
|
||||
|
@ -9,7 +10,7 @@ CONTACTS_DEFAULT_EMAIL_USAGES = getattr(settings, 'CONTACTS_DEFAULT_EMAIL_USAGES
|
|||
CONTACTS_DEFAULT_CITY = getattr(settings, 'CONTACTS_DEFAULT_CITY', 'Barcelona')
|
||||
|
||||
|
||||
CONTACTS_DEFAULT_PROVINCE = getattr(settings, 'CONTACTS_DEFAULT_PROVINCE', 'Barcelona')
|
||||
CONTACTS_COUNTRIES = getattr(settings, 'CONTACTS_COUNTRIES', data.COUNTRIES)
|
||||
|
||||
|
||||
CONTACTS_DEFAULT_COUNTRY = getattr(settings, 'CONTACTS_DEFAULT_COUNTRY', 'Spain')
|
||||
CONTACTS_DEFAULT_COUNTRY = getattr(settings, 'CONTACTS_DEFAULT_COUNTRY', 'ES')
|
||||
|
|
|
@ -2,8 +2,7 @@ from django.db import models
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.core import services
|
||||
from orchestra.core.validators import (validate_ipv4_address, validate_ipv6_address,
|
||||
validate_hostname, validate_ascii)
|
||||
from orchestra.core.validators import validate_ipv4_address, validate_ipv6_address, validate_ascii
|
||||
from orchestra.utils.python import AttrDict
|
||||
|
||||
from . import settings, validators, utils
|
||||
|
@ -11,11 +10,11 @@ from . import settings, validators, utils
|
|||
|
||||
class Domain(models.Model):
|
||||
name = models.CharField(_("name"), max_length=256, unique=True,
|
||||
validators=[validate_hostname, validators.validate_allowed_domain],
|
||||
validators=[validators.validate_domain_name, validators.validate_allowed_domain],
|
||||
help_text=_("Domain or subdomain name."))
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||
related_name='domains', blank=True, help_text=_("Automatically selected for subdomains."))
|
||||
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomains')
|
||||
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomains', editable=False)
|
||||
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial,
|
||||
help_text=_("Serial number"))
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import re
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.core.validators import validate_hostname
|
||||
from orchestra.utils import paths
|
||||
from orchestra.utils.system import run
|
||||
|
||||
|
@ -23,6 +24,15 @@ def validate_allowed_domain(value):
|
|||
raise ValidationError(_("This domain name is not allowed"))
|
||||
|
||||
|
||||
def validate_domain_name(value):
|
||||
# SRV records may use '_' in the domain name
|
||||
value = value.lstrip('*.').replace('_', '')
|
||||
try:
|
||||
validate_hostname(value)
|
||||
except ValidationError:
|
||||
raise ValidationError(_("Not a valid domain name."))
|
||||
|
||||
|
||||
def validate_zone_interval(value):
|
||||
try:
|
||||
int(value)
|
||||
|
|
|
@ -24,6 +24,11 @@ class PaymentMethod(plugins.Plugin):
|
|||
plugins.append(import_class(cls))
|
||||
return plugins
|
||||
|
||||
@classmethod
|
||||
def clean_data(cls, data):
|
||||
""" model clean """
|
||||
return data
|
||||
|
||||
def get_form(self):
|
||||
self.form.plugin = self
|
||||
self.form.plugin_field = 'method'
|
||||
|
|
|
@ -23,24 +23,12 @@ class SEPADirectDebitForm(PluginDataForm):
|
|||
widget=forms.TextInput(attrs={'size': '50'}))
|
||||
name = forms.CharField(max_length=128, label=_("Name"),
|
||||
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):
|
||||
iban = serializers.CharField(label='IBAN', validators=[IBANValidator()],
|
||||
min_length=min(IBAN_COUNTRY_CODE_LENGTH.values()), max_length=34)
|
||||
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):
|
||||
|
@ -56,6 +44,13 @@ class SEPADirectDebit(PaymentMethod):
|
|||
return _("This bill will been automatically charged to your bank account "
|
||||
" with IBAN number<br><strong>%s</strong>.") % source.number
|
||||
|
||||
@classmethod
|
||||
def clean_data(cls, data):
|
||||
data['iban'] = data['iban'].strip()
|
||||
data['name'] = data['name'].strip()
|
||||
IBANValidator()(data['iban'])
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def process(cls, transactions):
|
||||
debts = []
|
||||
|
|
|
@ -49,6 +49,9 @@ class PaymentSource(models.Model):
|
|||
|
||||
def get_due_delta(self):
|
||||
return self.method_class().due_delta
|
||||
|
||||
def clean(self):
|
||||
self.data = self.method_class().clean_data(self.data)
|
||||
|
||||
|
||||
class TransactionQuerySet(models.QuerySet):
|
||||
|
|
|
@ -23,7 +23,7 @@ class SystemUserQuerySet(models.QuerySet):
|
|||
class SystemUser(models.Model):
|
||||
""" System users """
|
||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
|
||||
help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."),
|
||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||
_("Enter a valid username."), 'invalid')])
|
||||
password = models.CharField(_("password"), max_length=128)
|
||||
|
|
|
@ -61,6 +61,14 @@ WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', {
|
|||
})
|
||||
|
||||
|
||||
WEBAPPS_TYPES_OVERRIDE = getattr(settings, 'WEBAPPS_TYPES_OVERRIDE', {})
|
||||
for webapp_type, value in WEBAPPS_TYPES_OVERRIDE.iteritems():
|
||||
if value is None:
|
||||
WEBAPPS_TYPES.pop(webapp_type, None)
|
||||
else:
|
||||
WEBAPPS_TYPES[webapp_type] = value
|
||||
|
||||
|
||||
WEBAPPS_DEFAULT_TYPE = getattr(settings, 'WEBAPPS_DEFAULT_TYPE', 'php5.5')
|
||||
|
||||
|
||||
|
@ -74,51 +82,91 @@ WEBAPPS_OPTIONS = getattr(settings, 'WEBAPPS_OPTIONS', {
|
|||
# PHP
|
||||
'enabled_functions': (
|
||||
_("PHP - Enabled functions"),
|
||||
r'^[\w.,-]+$'
|
||||
),
|
||||
'PHP-register_globals': (
|
||||
_("PHP - Register globals"),
|
||||
r'^(On|Off|on|off)$'
|
||||
r'^[\w\.,-]+$'
|
||||
),
|
||||
'PHP-allow_url_include': (
|
||||
_("PHP - Allow URL include"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-allow_url_fopen': (
|
||||
_("PHP - allow_url_fopen"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-auto_append_file': (
|
||||
_("PHP - Auto append file"),
|
||||
r'^none$'
|
||||
r'^[\w\.,-/]+$'
|
||||
),
|
||||
'PHP-auto_prepend_file': (
|
||||
_("PHP - Auto prepend file"),
|
||||
r'^[\w\.,-/]+$'
|
||||
),
|
||||
'PHP-date.timezone': (
|
||||
_("PHP - date.timezone"),
|
||||
r'^\w+/\w+$'
|
||||
),
|
||||
'PHP-default_socket_timeout': (
|
||||
_("PHP - Default socket timeout"),
|
||||
r'P^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'PHP-display_errors': (
|
||||
_("PHP - Display errors"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-extension': (
|
||||
_("PHP - Extension"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
'PHP-magic_quotes_gpc': (
|
||||
_("PHP - Magic quotes GPC"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-magic_quotes_runtime': (
|
||||
_("PHP - Magic quotes runtime"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-magic_quotes_sybase': (
|
||||
_("PHP - Magic quotes sybase"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-max_execution_time': (
|
||||
_("PHP - Max execution time"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'PHP-max_input_time': (
|
||||
_("PHP - Max input time"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'PHP-memory_limit': (
|
||||
_("PHP - Memory limit"),
|
||||
r'^[0-9][0-9]?[0-9]?M$'
|
||||
r'^[0-9]{1,3}M$'
|
||||
),
|
||||
'PHP-mysql.connect_timeout': (
|
||||
_("PHP - Mysql connect timeout"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^([0-9]){1,3}$'
|
||||
),
|
||||
'PHP-output_buffering': (
|
||||
_("PHP - output_buffering"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-register_globals': (
|
||||
_("PHP - Register globals"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-post_max_size': (
|
||||
_("PHP - Post max size"),
|
||||
r'^[0-9][0-9]?M$'
|
||||
r'^[0-9]{1,3}M$'
|
||||
),
|
||||
'PHP-sendmail_path': (
|
||||
_("PHP - sendmail_path"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
'PHP-session.bug_compat_warn': (
|
||||
_("PHP - session.bug_compat_warn"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-session.auto_start': (
|
||||
_("PHP - session.auto_start"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-safe_mode': (
|
||||
_("PHP - Safe mode"),
|
||||
|
@ -126,32 +174,48 @@ WEBAPPS_OPTIONS = getattr(settings, 'WEBAPPS_OPTIONS', {
|
|||
),
|
||||
'PHP-suhosin.post.max_vars': (
|
||||
_("PHP - Suhosin post max vars"),
|
||||
r'^[0-9][0-9]?[0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,4}$'
|
||||
),
|
||||
'PHP-suhosin.request.max_vars': (
|
||||
_("PHP - Suhosin request max vars"),
|
||||
r'^[0-9][0-9]?[0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,4}$'
|
||||
),
|
||||
'PHP-suhosin.session.encrypt': (
|
||||
_("PHP - suhosin.session.encrypt"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-suhosin.simulation': (
|
||||
_("PHP - Suhosin simulation"),
|
||||
r'^(On|Off|on|off)$'
|
||||
),
|
||||
'PHP-suhosin.executor.include.whitelist': (
|
||||
_("PHP - suhosin.executor.include.whitelist"),
|
||||
r'^(upload|phar)$'
|
||||
),
|
||||
'PHP-upload_max_filesize': (
|
||||
_("PHP - upload_max_filesize"),
|
||||
r'^[0-9]{1,3}M$'
|
||||
),
|
||||
'PHP-zend_extension': (
|
||||
_("PHP - zend_extension"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
# FCGID
|
||||
'FcgidIdleTimeout': (
|
||||
_("FCGI - Idle timeout"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidBusyTimeout': (
|
||||
_("FCGI - Busy timeout"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidConnectTimeout': (
|
||||
_("FCGI - Connection timeout"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
'FcgidIOTimeout': (
|
||||
_("FCGI - IO timeout"),
|
||||
r'^[0-9][0-9]?[0-9]?$'
|
||||
r'^[0-9]{1,3}$'
|
||||
),
|
||||
})
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ class Apache2Backend(ServiceController):
|
|||
if site.protocol is 'https':
|
||||
extra_conf += self.get_ssl(site)
|
||||
extra_conf += self.get_security(site)
|
||||
extra_conf += self.get_redirect(site)
|
||||
context['extra_conf'] = extra_conf
|
||||
|
||||
apache_conf = Template(textwrap.dedent("""\
|
||||
|
@ -89,7 +90,7 @@ class Apache2Backend(ServiceController):
|
|||
<Directory %(app_path)s>
|
||||
Options +ExecCGI
|
||||
AddHandler fcgid-script .php
|
||||
FcgidWrapper %(fcgid_path)s
|
||||
FcgidWrapper %(fcgid_path)s\
|
||||
""" % context)
|
||||
for option in content.webapp.options.filter(name__startswith='Fcgid'):
|
||||
fcgid += " %s %s\n" % (option.name, option.value)
|
||||
|
@ -101,10 +102,12 @@ class Apache2Backend(ServiceController):
|
|||
custom_cert = site.options.filter(name='ssl')
|
||||
if custom_cert:
|
||||
cert = tuple(custom_cert[0].value.split())
|
||||
# TODO separate directtives?
|
||||
directives = textwrap.dedent("""\
|
||||
SSLEngine on
|
||||
SSLCertificateFile %s
|
||||
SSLCertificateKeyFile %s""" % cert
|
||||
SSLCertificateKeyFile %s\
|
||||
""" % cert
|
||||
)
|
||||
return directives
|
||||
|
||||
|
@ -112,14 +115,24 @@ class Apache2Backend(ServiceController):
|
|||
directives = ''
|
||||
for rules in site.options.filter(name='sec_rule_remove'):
|
||||
for rule in rules.value.split():
|
||||
directives += "SecRuleRemoveById %i" % int(rule)
|
||||
|
||||
directives += "SecRuleRemoveById %i\n" % int(rule)
|
||||
for modsecurity in site.options.filter(name='sec_rule_off'):
|
||||
directives += textwrap.dedent("""\
|
||||
<LocationMatch %s>
|
||||
SecRuleEngine Off
|
||||
</LocationMatch>
|
||||
</LocationMatch>\
|
||||
""" % modsecurity.value)
|
||||
if directives:
|
||||
directives = '<IfModule mod_security2.c>\n%s\n</IfModule>' % directives
|
||||
return directives
|
||||
|
||||
def get_redirect(self, site):
|
||||
directives = ''
|
||||
for redirect in site.options.filter(name='redirect'):
|
||||
if re.match(r'^.*[\^\*\$\?\)]+.*$', redirect.value):
|
||||
directives += "RedirectMatch %s" % redirect.value
|
||||
else:
|
||||
directives += "Redirect %s" % redirect.value
|
||||
return directives
|
||||
|
||||
def get_protections(self, site):
|
||||
|
|
|
@ -17,25 +17,34 @@ WEBSITES_DEFAULT_IP = getattr(settings, 'WEBSITES_DEFAULT_IP', '*')
|
|||
WEBSITES_DOMAIN_MODEL = getattr(settings, 'WEBSITES_DOMAIN_MODEL', 'domains.Domain')
|
||||
|
||||
|
||||
# TODO ssl ca, ssl cert, ssl key
|
||||
WEBSITES_OPTIONS = getattr(settings, 'WEBSITES_OPTIONS', {
|
||||
# { name: ( verbose_name, validation_regex ) }
|
||||
'directory_protection': (
|
||||
_("HTTPD - Directory protection"),
|
||||
r'^([\w/_]+)\s+(\".*\")\s+([\w/_\.]+)$'
|
||||
),
|
||||
'redirection': (
|
||||
'redirect': (
|
||||
_("HTTPD - Redirection"),
|
||||
r'^.*\s+.*$'
|
||||
r'^(permanent\s[^ ]+|[^ ]+)\s[^ ]+$'
|
||||
),
|
||||
'ssl': (
|
||||
_("HTTPD - SSL"),
|
||||
r'^.*\s+.*$'
|
||||
'ssl_ca': (
|
||||
_("HTTPD - SSL CA"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
'ssl_cert': (
|
||||
_("HTTPD - SSL cert"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
'ssl_key': (
|
||||
_("HTTPD - SSL key"),
|
||||
r'^[^ ]+$'
|
||||
),
|
||||
'sec_rule_remove': (
|
||||
_("HTTPD - SecRuleRemoveById"),
|
||||
r'^[0-9,\s]+$'
|
||||
r'^[0-9\s]+$'
|
||||
),
|
||||
'sec_rule_off': (
|
||||
'sec_engine': (
|
||||
_("HTTPD - Disable Modsecurity"),
|
||||
r'^[\w/_]+$'
|
||||
),
|
||||
|
|
|
@ -155,7 +155,10 @@ function install_requirements () {
|
|||
lxml==3.3.5 \
|
||||
python-dateutil==2.2 \
|
||||
django-iban==0.3.0 \
|
||||
requests"
|
||||
requests \
|
||||
phonenumbers \
|
||||
django-countries \
|
||||
django-localflavor"
|
||||
|
||||
if $testing; then
|
||||
APT="${APT} \
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import re
|
||||
|
||||
import crack
|
||||
import localflavor
|
||||
import phonenumbers
|
||||
|
||||
from django.core import validators
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from IPy import IP
|
||||
|
||||
from ..utils.python import import_class
|
||||
|
||||
|
||||
def validate_ipv4_address(value):
|
||||
msg = _("%s is not a valid IPv4 address") % value
|
||||
|
@ -18,7 +22,6 @@ def validate_ipv4_address(value):
|
|||
raise ValidationError(msg)
|
||||
|
||||
|
||||
|
||||
def validate_ipv6_address(value):
|
||||
msg = _("%s is not a valid IPv6 address") % value
|
||||
try:
|
||||
|
@ -61,11 +64,12 @@ def validate_hostname(hostname):
|
|||
http://stackoverflow.com/a/2532344
|
||||
"""
|
||||
if len(hostname) > 255:
|
||||
return False
|
||||
if hostname[-1] == ".":
|
||||
hostname = hostname[:-1] # strip exactly one dot from the right, if present
|
||||
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
||||
return all(allowed.match(x) for x in hostname.split("."))
|
||||
raise ValidationError(_("Too long for a hostname."))
|
||||
hostname = hostname.rstrip('.')
|
||||
allowed = re.compile('(?!-)[A-Z\d-]{1,63}(?<!-)$', re.IGNORECASE)
|
||||
for name in hostname.split('.'):
|
||||
if not allowed.match(name):
|
||||
raise ValidationError(_("Not a valid hostname (%s).") % name)
|
||||
|
||||
|
||||
def validate_password(value):
|
||||
|
@ -78,3 +82,40 @@ def validate_password(value):
|
|||
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)
|
||||
|
||||
|
||||
def validate_vat(vat, country):
|
||||
field = 'localflavor.{lower}.forms.{upper}IdentityCardNumberField'.format(
|
||||
lower=country.lower(),
|
||||
upper=country.upper()
|
||||
)
|
||||
try:
|
||||
field = import_class(field)
|
||||
except (ImportError, AttributeError, ValueError):
|
||||
pass
|
||||
else:
|
||||
field().clean(vat)
|
||||
|
||||
|
||||
def validate_zipcode(zipcode, country):
|
||||
field = 'localflavor.{lower}.forms.{upper}PostalCodeField'.format(
|
||||
lower=country.lower(),
|
||||
upper=country.upper()
|
||||
)
|
||||
try:
|
||||
field = import_class(field)
|
||||
except (ImportError, AttributeError, ValueError):
|
||||
pass
|
||||
else:
|
||||
field().clean(zipcode)
|
||||
|
||||
|
||||
def validate_phone(value, country):
|
||||
""" local phone number or international """
|
||||
msg = _("Not a valid %s nor international phone number.") % country
|
||||
try:
|
||||
number = phonenumbers.parse(value, country)
|
||||
except phonenumbers.phonenumberutil.NumberParseException:
|
||||
raise ValidationError(msg)
|
||||
if not phonenumbers.is_valid_number(number):
|
||||
raise ValidationError(msg)
|
||||
|
|
|
@ -29,6 +29,10 @@ class MultiSelectField(models.CharField):
|
|||
|
||||
def to_python(self, value):
|
||||
if value is not None:
|
||||
if isinstance(value, list) and value[0].startswith('('):
|
||||
# Workaround unknown bug on default model values
|
||||
# [u"('SUPPORT'", u" 'ADMIN'", u" 'BILLING'", u" 'TECH'", u" 'ADDS'", u" 'EMERGENCY')"]
|
||||
value = list(eval(', '.join(value)))
|
||||
return value if isinstance(value, list) else value.split(',')
|
||||
return ''
|
||||
|
||||
|
@ -36,7 +40,7 @@ class MultiSelectField(models.CharField):
|
|||
super(MultiSelectField, self).contribute_to_class(cls, name)
|
||||
if self.choices:
|
||||
def func(self, field=name, choices=dict(self.choices)):
|
||||
','.join([ choices.get(value, value) for value in getattr(self, field) ])
|
||||
return ','.join([ choices.get(value, value) for value in getattr(self, field) ])
|
||||
setattr(cls, 'get_%s_display' % self.name, func)
|
||||
|
||||
def validate(self, value, model_instance):
|
||||
|
|
|
@ -21,11 +21,11 @@ def check_root(func):
|
|||
return wrapped
|
||||
|
||||
|
||||
class _AttributeString(str):
|
||||
class _AttributeUnicode(unicode):
|
||||
""" Simple string subclass to allow arbitrary attribute access. """
|
||||
@property
|
||||
def stdout(self):
|
||||
return str(self)
|
||||
return unicode(self)
|
||||
|
||||
|
||||
def make_async(fd):
|
||||
|
@ -43,7 +43,7 @@ def read_async(fd):
|
|||
if e.errno != errno.EAGAIN:
|
||||
raise e
|
||||
else:
|
||||
return ''
|
||||
return u''
|
||||
|
||||
|
||||
def run(command, display=False, error_codes=[0], silent=False, stdin=''):
|
||||
|
@ -60,8 +60,8 @@ def run(command, display=False, error_codes=[0], silent=False, stdin=''):
|
|||
make_async(p.stdout)
|
||||
make_async(p.stderr)
|
||||
|
||||
stdout = str()
|
||||
stderr = str()
|
||||
stdout = unicode()
|
||||
stderr = unicode()
|
||||
|
||||
# Async reading of stdout and sterr
|
||||
while True:
|
||||
|
@ -77,15 +77,15 @@ def run(command, display=False, error_codes=[0], silent=False, stdin=''):
|
|||
if display and stderrPiece:
|
||||
sys.stderr.write(stderrPiece)
|
||||
|
||||
stdout += stdoutPiece
|
||||
stderr += stderrPiece
|
||||
stdout += stdoutPiece.decode("utf8")
|
||||
stderr += stderrPiece.decode("utf8")
|
||||
returnCode = p.poll()
|
||||
|
||||
if returnCode != None:
|
||||
break
|
||||
|
||||
out = _AttributeString(stdout.strip())
|
||||
err = _AttributeString(stderr.strip())
|
||||
out = _AttributeUnicode(stdout.strip())
|
||||
err = _AttributeUnicode(stderr.strip())
|
||||
p.stdout.close()
|
||||
p.stderr.close()
|
||||
|
||||
|
|
|
@ -1,6 +1,99 @@
|
|||
import re
|
||||
import glob
|
||||
|
||||
import sys
|
||||
import errno
|
||||
import fcntl
|
||||
import getpass
|
||||
import os
|
||||
import re
|
||||
import select
|
||||
import subprocess
|
||||
import textwrap
|
||||
|
||||
class _AttributeString(str):
|
||||
""" Simple string subclass to allow arbitrary attribute access. """
|
||||
@property
|
||||
def stdout(self):
|
||||
return str(self)
|
||||
|
||||
|
||||
def make_async(fd):
|
||||
""" Helper function to add the O_NONBLOCK flag to a file descriptor """
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||
|
||||
|
||||
def read_async(fd):
|
||||
"""
|
||||
Helper function to read some data from a file descriptor, ignoring EAGAIN errors
|
||||
"""
|
||||
try:
|
||||
return fd.read()
|
||||
except IOError, e:
|
||||
if e.errno != errno.EAGAIN:
|
||||
raise e
|
||||
else:
|
||||
return ''
|
||||
|
||||
def run(command, display=False, error_codes=[0], silent=False, stdin=''):
|
||||
""" Subprocess wrapper for running commands """
|
||||
if display:
|
||||
sys.stderr.write("\n\033[1m $ %s\033[0m\n" % command)
|
||||
|
||||
p = subprocess.Popen(command, shell=True, executable='/bin/bash',
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
|
||||
p.stdin.write(stdin)
|
||||
p.stdin.close()
|
||||
|
||||
make_async(p.stdout)
|
||||
make_async(p.stderr)
|
||||
|
||||
stdout = str()
|
||||
stderr = str()
|
||||
|
||||
# Async reading of stdout and sterr
|
||||
while True:
|
||||
# Wait for data to become available
|
||||
select.select([p.stdout, p.stderr], [], [])
|
||||
|
||||
# Try reading some data from each
|
||||
stdoutPiece = read_async(p.stdout)
|
||||
stderrPiece = read_async(p.stderr)
|
||||
|
||||
if display and stdoutPiece:
|
||||
sys.stdout.write(stdoutPiece)
|
||||
if display and stderrPiece:
|
||||
sys.stderr.write(stderrPiece)
|
||||
|
||||
stdout += stdoutPiece
|
||||
stderr += stderrPiece
|
||||
returnCode = p.poll()
|
||||
|
||||
if returnCode != None:
|
||||
break
|
||||
|
||||
out = _AttributeString(stdout.strip())
|
||||
err = _AttributeString(stderr.strip())
|
||||
p.stdout.close()
|
||||
p.stderr.close()
|
||||
|
||||
out.failed = False
|
||||
out.return_code = returnCode
|
||||
out.stderr = err
|
||||
if p.returncode not in error_codes:
|
||||
out.failed = True
|
||||
msg = "\nrun() encountered an error (return code %s) while executing '%s'\n"
|
||||
msg = msg % (p.returncode, command)
|
||||
if display:
|
||||
sys.stderr.write("\n\033[1;31mCommandError: %s %s\033[m\n" % (msg, err))
|
||||
if not silent:
|
||||
raise AttributeError("%s %s %s" % (msg, err, out))
|
||||
|
||||
out.succeeded = not out.failed
|
||||
return out
|
||||
|
||||
|
||||
|
||||
print "from orchestra.apps.accounts.models import Account"
|
||||
print "from orchestra.apps.domains.models import Domain"
|
||||
|
@ -8,10 +101,24 @@ print "from orchestra.apps.webapps.models import WebApp"
|
|||
print "from orchestra.apps.websites.models import Website, Content"
|
||||
|
||||
|
||||
def print_webapp(context):
|
||||
print textwrap.dedent("""\
|
||||
try:
|
||||
webapp = WebApp.objects.get(account=account, name='%(name)s')
|
||||
except:"
|
||||
webapp = WebApp.objects.create(account=account, name='%(name)s', type='%(type)s')
|
||||
else:
|
||||
webapp.type = '%(type)s'
|
||||
webapp.save()"
|
||||
Content.objects.get_or_create(website=website, webapp=webapp, path='%(path)s')
|
||||
""" % context
|
||||
)
|
||||
|
||||
|
||||
for conf in glob.glob('/etc/apache2/sites-enabled/*'):
|
||||
username = conf.split('/')[-1].split('.')[0]
|
||||
with open(conf, 'rb') as conf:
|
||||
print "account = Account.objects.get(user__username='%s')" % username
|
||||
print "account = Account.objects.get(username='%s')" % username
|
||||
for line in conf.readlines():
|
||||
line = line.strip()
|
||||
if line.startswith('<VirtualHost'):
|
||||
|
@ -20,43 +127,64 @@ for conf in glob.glob('/etc/apache2/sites-enabled/*'):
|
|||
apps = []
|
||||
if line.endswith(':443>'):
|
||||
port = 443
|
||||
wrapper_root = None
|
||||
webalizer = False
|
||||
webappname = None
|
||||
elif line.startswith("DocumentRoot"):
|
||||
__, path = line.split()
|
||||
webappname = path.rstrip('/').split('/')[-1]
|
||||
if webappname == 'public_html':
|
||||
webappname = ''
|
||||
elif line.startswith("ServerName"):
|
||||
domain = line.split()[1]
|
||||
name = domain
|
||||
__, domain = line.split()
|
||||
sitename = domain
|
||||
domains.append("'%s'" % domain)
|
||||
elif line.startswith("ServerAlias"):
|
||||
for domain in line.split()[1:]:
|
||||
domains.append("'%s'" % domain)
|
||||
elif line.startswith("Alias /fcgi-bin/"):
|
||||
fcgid = line.split('/')[-1] or line.split('/')[-2]
|
||||
fcgid = fcgid.split('-')[0]
|
||||
apps.append((name, fcgid, '/'))
|
||||
__, __, wrapper_root = line.split()
|
||||
elif line.startswith('Action php-fcgi'):
|
||||
__, __, wrapper_name = line.split()
|
||||
wrapper_name = wrapper_name.split('/')[-1]
|
||||
elif line.startswith("Alias /webalizer"):
|
||||
apps.append(('webalizer', 'webalizer', '/webalizer'))
|
||||
webalizer = True
|
||||
elif line == '</VirtualHost>':
|
||||
if port == 443:
|
||||
name += '-ssl'
|
||||
print "# SITE"
|
||||
print "website, __ = Website.objects.get_or_create(name='%s', account=account, port=%d)" % (name, port)
|
||||
domains = ', '.join(domains)
|
||||
print "for domain in [%s]:" % str(domains)
|
||||
print " try:"
|
||||
print " domain = Domain.objects.get(name=domain)"
|
||||
print " except:"
|
||||
print " domain = Domain.objects.create(name=domain, account=account)"
|
||||
print " else:"
|
||||
print " domain.account = account"
|
||||
print " domain.save()"
|
||||
print " website.domains.add(domain)"
|
||||
print ""
|
||||
for name, type, path in apps:
|
||||
print "try:"
|
||||
print " webapp = WebApp.objects.get(account=account, name='%s')" % name
|
||||
print "except:"
|
||||
print " webapp = WebApp.objects.create(account=account, name='%s', type='%s')" % (name, type)
|
||||
print "else:"
|
||||
print " webapp.type = '%s'" % type
|
||||
print " webapp.save()"
|
||||
print ""
|
||||
print "Content.objects.get_or_create(website=website, webapp=webapp, path='%s')" % path
|
||||
sitename += '-ssl'
|
||||
context = {
|
||||
'sitename': sitename,
|
||||
'port': port,
|
||||
'domains': ', '.join(domains),
|
||||
}
|
||||
print textwrap.dedent("""\
|
||||
# SITE"
|
||||
website, __ = Website.objects.get_or_create(name='%(sitename)s', account=account, port=%(port)d)
|
||||
for domain in [%(domains)s]:
|
||||
try:
|
||||
domain = Domain.objects.get(name=domain)
|
||||
except:
|
||||
domain = Domain.objects.create(name=domain, account=account)
|
||||
else:
|
||||
domain.account = account
|
||||
domain.save()
|
||||
website.domains.add(domain)
|
||||
""" % context)
|
||||
if wrapper_root:
|
||||
wrapper = os.join(wrapper_root, wrapper_name)
|
||||
fcgid = run('grep "^\s*exec " %s' % wrapper).stdout
|
||||
type = fcgid.split()[1].split('/')[-1].split('-')[0]
|
||||
for option in fcgid.split('-d'):
|
||||
print option
|
||||
print_webapp({
|
||||
'name': webappname,
|
||||
'path': '/',
|
||||
'type': type,
|
||||
})
|
||||
if webalizer:
|
||||
print_webapp({
|
||||
'name': 'webalizer-%s' % sitename,
|
||||
'path': '/webalizer',
|
||||
'type': 'webalizer',
|
||||
})
|
||||
print '\n'
|
||||
|
|
|
@ -1,34 +1,64 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
VIRTUALTABLE="/etc/postfix/virtusertable"
|
||||
VIRTUALTABLE=${1-"/etc/postfix/virtusertable"}
|
||||
|
||||
|
||||
echo "from orchestra.apps.users import User"
|
||||
echo "from orchestra.apps.users.roles.mailbox import Address, Mailbox"
|
||||
echo "from orchestra.apps.domains import Domain"
|
||||
echo "from orchestra.apps.accounts.models import Account"
|
||||
echo "from orchestra.apps.mailboxes.models import Address, Mailbox"
|
||||
echo "from orchestra.apps.domains.models import Domain"
|
||||
|
||||
echo "main_account = Account.objects.get(id=1)"
|
||||
cat "$VIRTUALTABLE"|grep -v "^\s*$"|while read line; do
|
||||
NAME=$(echo "$line" | awk {'print $1'} | cut -d'@' -f1)
|
||||
DOMAIN=$(echo "$line" | awk {'print $1'} | cut -d'@' -f2)
|
||||
DESTINATION=$(echo "$line" | awk '{$1=""; print $0}' | sed -e 's/^ *//' -e 's/ *$//')
|
||||
echo "domain = Domain.objects.get(name='$DOMAIN')"
|
||||
echo "mailboxes = []"
|
||||
echo "account = main_account"
|
||||
NEW_DESTINATION=""
|
||||
for PLACE in $DESTINATION; do
|
||||
if [[ ! $(echo $PLACE | grep '@') ]]; then
|
||||
echo "try:"
|
||||
echo " user = User.objects.get(username='$PLACE')"
|
||||
echo "except:"
|
||||
echo " print 'User $PLACE does not exists'"
|
||||
echo "else:"
|
||||
echo " mailbox, __ = Mailbox.objects.get_or_create(user=user)"
|
||||
echo " if user.account_id != 1:"
|
||||
echo " user.account=domain.account"
|
||||
echo " user.save()"
|
||||
echo ""
|
||||
if [[ $(grep "^${PLACE}:" /etc/shadow) ]]; then
|
||||
PASSWORD=$(grep "^${PLACE}:" /etc/shadow | cut -d':' -f2)
|
||||
echo "if account == main_account and domain.account != main_account:"
|
||||
echo " account = domain.account"
|
||||
echo "else:"
|
||||
echo " try:"
|
||||
echo " account = Account.objects.get(username='${PLACE}')"
|
||||
echo " except:"
|
||||
echo " pass"
|
||||
echo "mailboxes.append(('${PLACE}', '${PASSWORD}'))"
|
||||
else
|
||||
NEW_DESTINATION="${NEW_DESTINATION} ${PLACE}"
|
||||
fi
|
||||
else
|
||||
NEW_DESTINATION="${NEW_DESTINATION} ${PLACE}"
|
||||
fi
|
||||
done
|
||||
echo "address, __ = Address.objects.get_or_create(name='$NAME', domain=domain)"
|
||||
echo "address.account=domain.account"
|
||||
echo "address.destination='$DESTINATION'"
|
||||
echo "address.save()"
|
||||
echo "for mailbox, password in mailboxes:"
|
||||
echo " mailbox = mailbox.strip()"
|
||||
echo " try:"
|
||||
echo " mailbox = Mailbox.objects.get(username=mailbox)"
|
||||
echo " except:"
|
||||
echo " mailbox = Mailbox(username=mailbox, password=password, account=account)"
|
||||
echo " try:"
|
||||
echo " mailbox.full_clean()"
|
||||
echo " except:"
|
||||
echo " sys.stderr.write('cleaning')"
|
||||
echo " else:"
|
||||
echo " mailbox.save()"
|
||||
echo " else:"
|
||||
echo " if mailbox.account != account:"
|
||||
echo " sys.stderr.write('%s != %s' % (mailbox.account, account))"
|
||||
echo " if domain.account != account:"
|
||||
echo " sys.stderr.write('%s != %s' % (domain.account, account))"
|
||||
echo " address = Address(name='${NAME}', domain=domain, account=account, destination='${NEW_DESTINATION}')"
|
||||
echo " try:"
|
||||
echo " address.full_clean()"
|
||||
echo " except:"
|
||||
echo " sys.stderr.write('cleaning address')"
|
||||
echo " else:"
|
||||
echo " address.save()"
|
||||
echo " domain = None"
|
||||
done
|
||||
|
|
Loading…
Reference in New Issue