Random fixes
This commit is contained in:
parent
13cf3a41ed
commit
0d63a4ddad
2
TODO.md
2
TODO.md
|
@ -354,4 +354,4 @@ make django admin taskstate uncollapse fucking traceback, ( if exists ?)
|
||||||
|
|
||||||
# backend.context and backned.instance provided when an action is called? like forms.cleaned_data: do it on manager.generation(backend.context = backend.get_context()) or in backend.__getattr__ ? also backend.head,tail,content switching on manager.generate()?
|
# backend.context and backned.instance provided when an action is called? like forms.cleaned_data: do it on manager.generation(backend.context = backend.get_context()) or in backend.__getattr__ ? also backend.head,tail,content switching on manager.generate()?
|
||||||
|
|
||||||
# replace return_code by exit_code everywhere
|
resorce monitoring more efficient, less mem an better queries for calc current data
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
|
||||||
|
from .decorators import action_with_confirmation
|
||||||
from .forms import SendEmailForm
|
from .forms import SendEmailForm
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,3 +108,25 @@ class SendEmail(object):
|
||||||
})
|
})
|
||||||
# Display the confirmation page
|
# Display the confirmation page
|
||||||
return render(request, self.template, self.context)
|
return render(request, self.template, self.context)
|
||||||
|
|
||||||
|
|
||||||
|
@action_with_confirmation()
|
||||||
|
def disable(modeladmin, request, queryset):
|
||||||
|
num = 0
|
||||||
|
for obj in queryset:
|
||||||
|
obj.disable()
|
||||||
|
modeladmin.log_change(request, obj, _("Disabled"))
|
||||||
|
num += 1
|
||||||
|
opts = modeladmin.model._meta
|
||||||
|
context = {
|
||||||
|
'verbose_name': opts.verbose_name,
|
||||||
|
'verbose_name_plural': opts.verbose_name_plural,
|
||||||
|
'num': num
|
||||||
|
}
|
||||||
|
msg = ungettext(
|
||||||
|
_("Selected %(verbose_name)s and related services has been disabled.") % context,
|
||||||
|
_("%(num)s selected %(verbose_name_plural)s and related services have been disabled.") % context,
|
||||||
|
num)
|
||||||
|
modeladmin.message_user(request, msg)
|
||||||
|
disable.url_name = 'disable'
|
||||||
|
disable.verbose_name = _("Disable")
|
||||||
|
|
|
@ -12,28 +12,11 @@ from django.utils.html import format_html
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin.decorators import action_with_confirmation
|
|
||||||
from orchestra.core import services
|
from orchestra.core import services
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
@action_with_confirmation()
|
|
||||||
def disable(modeladmin, request, queryset):
|
|
||||||
num = 0
|
|
||||||
for account in queryset:
|
|
||||||
account.disable()
|
|
||||||
modeladmin.log_change(request, account, _("Disabled"))
|
|
||||||
num += 1
|
|
||||||
msg = ungettext(
|
|
||||||
_("Selected account and related services has been disabled."),
|
|
||||||
_("%s selected accounts and related services have been disabled.") % num,
|
|
||||||
num)
|
|
||||||
modeladmin.message_user(request, msg)
|
|
||||||
disable.url_name = 'disable'
|
|
||||||
disable.verbose_name = _("Disable")
|
|
||||||
|
|
||||||
|
|
||||||
def list_contacts(modeladmin, request, queryset):
|
def list_contacts(modeladmin, request, queryset):
|
||||||
ids = queryset.values_list('id', flat=True)
|
ids = queryset.values_list('id', flat=True)
|
||||||
if not ids:
|
if not ids:
|
||||||
|
|
|
@ -12,12 +12,12 @@ from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
from orchestra.admin.actions import SendEmail
|
from orchestra.admin.actions import SendEmail, disable
|
||||||
from orchestra.admin.utils import wrap_admin_view, admin_link, set_url_query, change_url
|
from orchestra.admin.utils import wrap_admin_view, admin_link, set_url_query, change_url
|
||||||
from orchestra.core import services, accounts
|
from orchestra.core import services, accounts
|
||||||
from orchestra.forms import UserChangeForm
|
from orchestra.forms import UserChangeForm
|
||||||
|
|
||||||
from .actions import disable, list_contacts, service_report, delete_related_services
|
from .actions import list_contacts, service_report, delete_related_services
|
||||||
from .filters import HasMainUserListFilter
|
from .filters import HasMainUserListFilter
|
||||||
from .forms import AccountCreationForm
|
from .forms import AccountCreationForm
|
||||||
from .models import Account
|
from .models import Account
|
||||||
|
|
|
@ -114,7 +114,7 @@ class DomainTestMixin(object):
|
||||||
'server_addr': server_addr
|
'server_addr': server_addr
|
||||||
}
|
}
|
||||||
dig_soa = 'dig @%(server_addr)s %(domain_name)s|grep "\sSOA\s"'
|
dig_soa = 'dig @%(server_addr)s %(domain_name)s|grep "\sSOA\s"'
|
||||||
soa = run(dig_soa % context, error_codes=[0,1]).stdout
|
soa = run(dig_soa % context, valid_codes=(0, 1)).stdout
|
||||||
if soa:
|
if soa:
|
||||||
soa = soa.split()
|
soa = soa.split()
|
||||||
self.assertEqual('IN', soa[2])
|
self.assertEqual('IN', soa[2])
|
||||||
|
|
|
@ -118,11 +118,11 @@ def validate_zone(zone):
|
||||||
with open(zone_path, 'wb') as f:
|
with open(zone_path, 'wb') as f:
|
||||||
f.write(zone.encode('ascii'))
|
f.write(zone.encode('ascii'))
|
||||||
# Don't use /dev/stdin becuase the 'argument list is too long' error
|
# Don't use /dev/stdin becuase the 'argument list is too long' error
|
||||||
check = run(' '.join([checkzone, zone_name, zone_path]), error_codes=[0,1,127], display=False)
|
check = run(' '.join([checkzone, zone_name, zone_path]), valid_codes=(0,1,127), display=False)
|
||||||
finally:
|
finally:
|
||||||
os.unlink(zone_path)
|
os.unlink(zone_path)
|
||||||
if check.return_code == 127:
|
if check.exit_code == 127:
|
||||||
logger.error("Cannot validate domain zone: %s not installed." % checkzone)
|
logger.error("Cannot validate domain zone: %s not installed." % checkzone)
|
||||||
elif check.return_code == 1:
|
elif check.exit_code == 1:
|
||||||
errors = re.compile(r'zone.*: (.*)').findall(check.stdout)[:-1]
|
errors = re.compile(r'zone.*: (.*)').findall(check.stdout)[:-1]
|
||||||
raise ValidationError(', '.join(errors))
|
raise ValidationError(', '.join(errors))
|
||||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib.auth.admin import UserAdmin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
|
from orchestra.admin.actions import disable
|
||||||
from orchestra.admin.utils import admin_link
|
from orchestra.admin.utils import admin_link
|
||||||
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
||||||
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
||||||
|
@ -52,6 +53,7 @@ class ListAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModel
|
||||||
add_form = ListCreationForm
|
add_form = ListCreationForm
|
||||||
list_select_related = ('account', 'address_domain',)
|
list_select_related = ('account', 'address_domain',)
|
||||||
filter_by_account_fields = ['address_domain']
|
filter_by_account_fields = ['address_domain']
|
||||||
|
actions = (disable,)
|
||||||
|
|
||||||
address_domain_link = admin_link('address_domain', order='address_domain__name')
|
address_domain_link = admin_link('address_domain', order='address_domain__name')
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,10 @@ class List(models.Model):
|
||||||
def active(self):
|
def active(self):
|
||||||
return self.is_active and self.account.is_active
|
return self.is_active and self.account.is_active
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.is_active = False
|
||||||
|
self.save(update_fields=('is_active',))
|
||||||
|
|
||||||
def get_address_name(self):
|
def get_address_name(self):
|
||||||
return self.address_name or self.name
|
return self.address_name or self.name
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.db.models.functions import Concat
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
|
from orchestra.admin.actions import disable
|
||||||
from orchestra.admin.utils import admin_link, change_url
|
from orchestra.admin.utils import admin_link, change_url
|
||||||
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
||||||
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
||||||
|
@ -65,6 +66,12 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
add_form = MailboxCreationForm
|
add_form = MailboxCreationForm
|
||||||
form = MailboxChangeForm
|
form = MailboxChangeForm
|
||||||
list_prefetch_related = ('addresses__domain',)
|
list_prefetch_related = ('addresses__domain',)
|
||||||
|
actions = (disable,)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(MailboxAdmin, self).__init__(*args, **kwargs)
|
||||||
|
if settings.MAILBOXES_LOCAL_ADDRESS_DOMAIN:
|
||||||
|
type(self).actions = self.actions + (SendMailboxEmail(),)
|
||||||
|
|
||||||
def display_addresses(self, mailbox):
|
def display_addresses(self, mailbox):
|
||||||
addresses = []
|
addresses = []
|
||||||
|
@ -82,13 +89,6 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
display_filtering.admin_order_field = 'filtering'
|
display_filtering.admin_order_field = 'filtering'
|
||||||
display_filtering.allow_tags = True
|
display_filtering.allow_tags = True
|
||||||
|
|
||||||
def get_actions(self, request):
|
|
||||||
if settings.MAILBOXES_LOCAL_ADDRESS_DOMAIN:
|
|
||||||
type(self).actions = (SendMailboxEmail(),)
|
|
||||||
else:
|
|
||||||
type(self).actions = ()
|
|
||||||
return super(MailboxAdmin, self).get_actions(request)
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
if db_field.name == 'filtering':
|
if db_field.name == 'filtering':
|
||||||
kwargs['widget'] = OpenCustomFilteringOnSelect()
|
kwargs['widget'] = OpenCustomFilteringOnSelect()
|
||||||
|
|
|
@ -42,6 +42,10 @@ class Mailbox(models.Model):
|
||||||
except type(self).account.field.rel.to.DoesNotExist:
|
except type(self).account.field.rel.to.DoesNotExist:
|
||||||
return self.is_active
|
return self.is_active
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.is_active = False
|
||||||
|
self.save(update_fields=('is_active',))
|
||||||
|
|
||||||
def set_password(self, raw_password):
|
def set_password(self, raw_password):
|
||||||
self.password = make_password(raw_password)
|
self.password = make_password(raw_password)
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ def validate_sieve(value):
|
||||||
test = run(' '.join([sievetest, test_path, '/dev/null']), silent=True)
|
test = run(' '.join([sievetest, test_path, '/dev/null']), silent=True)
|
||||||
finally:
|
finally:
|
||||||
os.unlink(test_path)
|
os.unlink(test_path)
|
||||||
if test.return_code:
|
if test.exit_code:
|
||||||
errors = []
|
errors = []
|
||||||
for line in test.stderr.decode('utf8').splitlines():
|
for line in test.stderr.decode('utf8').splitlines():
|
||||||
error = re.match(r'^.*(line\s+[0-9]+:.*)', line)
|
error = re.match(r'^.*(line\s+[0-9]+:.*)', line)
|
||||||
|
|
|
@ -3,13 +3,13 @@ from orchestra.contrib.settings import Setting
|
||||||
|
|
||||||
PLANS_RATE_METHODS = Setting('PLANS_RATE_METHODS',
|
PLANS_RATE_METHODS = Setting('PLANS_RATE_METHODS',
|
||||||
(
|
(
|
||||||
'orchestra.contrib.plans.rating.step_price',
|
'orchestra.contrib.plans.ratings.step_price',
|
||||||
'orchestra.contrib.plans.rating.match_price',
|
'orchestra.contrib.plans.ratings.match_price',
|
||||||
'orchestra.contrib.plans.rating.best_price',
|
'orchestra.contrib.plans.ratings.best_price',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
PLANS_DEFAULT_RATE_METHOD = Setting('PLANS_DEFAULT_RATE_METHOD',
|
PLANS_DEFAULT_RATE_METHOD = Setting('PLANS_DEFAULT_RATE_METHOD',
|
||||||
'orchestra.contrib.plans.rating.step_price',
|
'orchestra.contrib.plans.ratings.step_price',
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from .backends import ServiceMonitor
|
||||||
|
|
||||||
@task(name='resources.Monitor')
|
@task(name='resources.Monitor')
|
||||||
def monitor(resource_id, ids=None):
|
def monitor(resource_id, ids=None):
|
||||||
with LockFile('/dev/shm/resources.monitor-%i.lock' % resource_id, expire=60*60):
|
with LockFile('/dev/shm/resources.monitor-%i.lock' % resource_id, expire=60*60, unlocked=bool(ids)):
|
||||||
from .models import ResourceData, Resource
|
from .models import ResourceData, Resource
|
||||||
resource = Resource.objects.get(pk=resource_id)
|
resource = Resource.objects.get(pk=resource_id)
|
||||||
resource_model = resource.content_type.model_class()
|
resource_model = resource.content_type.model_class()
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.contrib import admin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
|
from orchestra.admin.actions import disable
|
||||||
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
||||||
from orchestra.plugins.admin import SelectPluginAdminMixin
|
from orchestra.plugins.admin import SelectPluginAdminMixin
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
||||||
plugin = SoftwareService
|
plugin = SoftwareService
|
||||||
plugin_field = 'service'
|
plugin_field = 'service'
|
||||||
plugin_title = 'Software as a Service'
|
plugin_title = 'Software as a Service'
|
||||||
|
actions = (disable,)
|
||||||
|
|
||||||
def display_site_domain(self, saas):
|
def display_site_domain(self, saas):
|
||||||
site_domain = saas.get_site_domain()
|
site_domain = saas.get_site_domain()
|
||||||
|
|
|
@ -61,6 +61,10 @@ class SaaS(models.Model):
|
||||||
def active(self):
|
def active(self):
|
||||||
return self.is_active and self.account.is_active
|
return self.is_active and self.account.is_active
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.is_active = False
|
||||||
|
self.save(update_fields=('is_active',))
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if not self.pk:
|
if not self.pk:
|
||||||
self.name = self.name.lower()
|
self.name = self.name.lower()
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
nominal_price=28.10&
|
nominal_price=28.10&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=COMPENSATE&
|
on_cancel=COMPENSATE&
|
||||||
payment_style=PREPAY">Mailbox</option>
|
payment_style=PREPAY">Mailbox</option>
|
||||||
<option value="./?description=Mailbox%20allocated%20disk&
|
<option value="./?description=Mailbox%20allocated%20disk&
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
nominal_price=20.00&
|
nominal_price=20.00&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=&
|
pricing_period=&
|
||||||
rate_algorithm=MATCH_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.match_price&
|
||||||
on_cancel=DISCOUNT&
|
on_cancel=DISCOUNT&
|
||||||
payment_style=PREPAY">Mailbox allocated disk</option>
|
payment_style=PREPAY">Mailbox allocated disk</option>
|
||||||
<option value="./?description=Database&
|
<option value="./?description=Database&
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
nominal_price=24.79&
|
nominal_price=24.79&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=COMPENSATE&
|
on_cancel=COMPENSATE&
|
||||||
payment_style=PREPAY">Database</option>
|
payment_style=PREPAY">Database</option>
|
||||||
<option value="./?description=Basic%20domain&
|
<option value="./?description=Basic%20domain&
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
nominal_price=19.01&
|
nominal_price=19.01&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=NOTHING&
|
on_cancel=NOTHING&
|
||||||
payment_style=PREPAY">Basic domain</option>
|
payment_style=PREPAY">Basic domain</option>
|
||||||
<option value="./?description=Domain%20.cat%20extra&
|
<option value="./?description=Domain%20.cat%20extra&
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
nominal_price=26.59&
|
nominal_price=26.59&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=NOTHING&
|
on_cancel=NOTHING&
|
||||||
payment_style=PREPAY">Domain .cat extra</option>
|
payment_style=PREPAY">Domain .cat extra</option>
|
||||||
<option value="./?description=FTP%20account&
|
<option value="./?description=FTP%20account&
|
||||||
|
@ -112,7 +112,7 @@
|
||||||
nominal_price=28.10&
|
nominal_price=28.10&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=COMPENSATE&
|
on_cancel=COMPENSATE&
|
||||||
payment_style=PREPAY">FTP account</option>
|
payment_style=PREPAY">FTP account</option>
|
||||||
<option value="./?description=Traffic&
|
<option value="./?description=Traffic&
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
nominal_price=4.50&
|
nominal_price=4.50&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=MATCH_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.match_price&
|
||||||
on_cancel=NOTHING&
|
on_cancel=NOTHING&
|
||||||
payment_style=POSTPAY">Traffic</option>
|
payment_style=POSTPAY">Traffic</option>
|
||||||
<option value="./?description=Traffic%20prepay&
|
<option value="./?description=Traffic%20prepay&
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
nominal_price=3.00&
|
nominal_price=3.00&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=MONTHLY&
|
pricing_period=MONTHLY&
|
||||||
rate_algorithm=MATCH_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.match_price&
|
||||||
on_cancel=REFUND&
|
on_cancel=REFUND&
|
||||||
payment_style=PREPAY">Traffic prepay</option>
|
payment_style=PREPAY">Traffic prepay</option>
|
||||||
<option value="./?description=Development&
|
<option value="./?description=Development&
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
nominal_price=40.00&
|
nominal_price=40.00&
|
||||||
tax=21&
|
tax=21&
|
||||||
pricing_period=BILLING_PERIOD&
|
pricing_period=BILLING_PERIOD&
|
||||||
rate_algorithm=STEP_PRICE&
|
rate_algorithm=orchestra.contrib.plans.ratings.step_price&
|
||||||
on_cancel=NOTHING&
|
on_cancel=NOTHING&
|
||||||
payment_style=PREPAY">Develompent</option>
|
payment_style=PREPAY">Develompent</option>
|
||||||
{% endoneliner %}
|
{% endoneliner %}
|
||||||
|
|
|
@ -66,7 +66,7 @@ class SettingView(generic.edit.FormView):
|
||||||
if not self.request.POST.get('confirmation'):
|
if not self.request.POST.get('confirmation'):
|
||||||
settings_file = parser.get_settings_file()
|
settings_file = parser.get_settings_file()
|
||||||
new_content = parser.apply(changes)
|
new_content = parser.apply(changes)
|
||||||
diff = sys.run("cat <<EOF | diff %s -\n%s\nEOF" % (settings_file, new_content), error_codes=[1, 0]).stdout
|
diff = sys.run("cat <<EOF | diff %s -\n%s\nEOF" % (settings_file, new_content), valid_codes=(1, 0)).stdout
|
||||||
context = self.get_context_data(form=form)
|
context = self.get_context_data(form=form)
|
||||||
context['diff'] = diff
|
context['diff'] = diff
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.contrib import admin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
|
from orchestra.admin.actions import disable
|
||||||
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
|
||||||
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
from orchestra.contrib.accounts.filters import IsActiveListFilter
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
|
||||||
add_form = SystemUserCreationForm
|
add_form = SystemUserCreationForm
|
||||||
form = SystemUserChangeForm
|
form = SystemUserChangeForm
|
||||||
ordering = ('-id',)
|
ordering = ('-id',)
|
||||||
actions = (delete_selected, grant_permission,)
|
actions = (delete_selected, grant_permission, disable)
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
|
|
||||||
def display_main(self, user):
|
def display_main(self, user):
|
||||||
|
|
|
@ -68,6 +68,10 @@ class SystemUser(models.Model):
|
||||||
def has_shell(self):
|
def has_shell(self):
|
||||||
return self.shell not in settings.SYSTEMUSERS_DISABLED_SHELLS
|
return self.shell not in settings.SYSTEMUSERS_DISABLED_SHELLS
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.is_active = False
|
||||||
|
self.save(update_fields=('is_active',))
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return self.get_shell_display()
|
return self.get_shell_display()
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ class SystemUserMixin(object):
|
||||||
|
|
||||||
def validate_user(self, username):
|
def validate_user(self, username):
|
||||||
idcmd = sshr(self.MASTER_SERVER, "id %s" % username)
|
idcmd = sshr(self.MASTER_SERVER, "id %s" % username)
|
||||||
self.assertEqual(0, idcmd.return_code)
|
self.assertEqual(0, idcmd.exit_code)
|
||||||
user = SystemUser.objects.get(username=username)
|
user = SystemUser.objects.get(username=username)
|
||||||
groups = list(user.groups.values_list('username', flat=True))
|
groups = list(user.groups.values_list('username', flat=True))
|
||||||
groups.append(user.username)
|
groups.append(user.username)
|
||||||
|
@ -336,7 +336,7 @@ class AdminSystemUserTest(AdminSystemUserMixin, BaseLiveServerTestCase):
|
||||||
self.assertNotEqual(url, self.selenium.current_url)
|
self.assertNotEqual(url, self.selenium.current_url)
|
||||||
|
|
||||||
self.addCleanup(self.delete_account, account_username)
|
self.addCleanup(self.delete_account, account_username)
|
||||||
self.assertEqual(0, sshr(self.MASTER_SERVER, "id %s" % account_username).return_code)
|
self.assertEqual(0, sshr(self.MASTER_SERVER, "id %s" % account_username).exit_code)
|
||||||
|
|
||||||
@snapshot_on_error
|
@snapshot_on_error
|
||||||
def test_delete_account(self):
|
def test_delete_account(self):
|
||||||
|
|
|
@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
|
from orchestra.admin.actions import disable
|
||||||
from orchestra.admin.utils import admin_link, change_url
|
from orchestra.admin.utils import admin_link, change_url
|
||||||
from orchestra.contrib.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
from orchestra.contrib.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
@ -68,6 +69,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
filter_by_account_fields = ['domains']
|
filter_by_account_fields = ['domains']
|
||||||
list_prefetch_related = ('domains', 'content_set__webapp')
|
list_prefetch_related = ('domains', 'content_set__webapp')
|
||||||
search_fields = ('name', 'account__username', 'domains__name', 'content__webapp__name')
|
search_fields = ('name', 'account__username', 'domains__name', 'content__webapp__name')
|
||||||
|
actions = (disable,)
|
||||||
|
|
||||||
def display_domains(self, website):
|
def display_domains(self, website):
|
||||||
domains = []
|
domains = []
|
||||||
|
|
|
@ -51,6 +51,10 @@ class Website(models.Model):
|
||||||
def active(self):
|
def active(self):
|
||||||
return self.is_active and self.account.is_active
|
return self.is_active and self.account.is_active
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.is_active = False
|
||||||
|
self.save(update_fields=('is_active',))
|
||||||
|
|
||||||
def get_settings_context(self):
|
def get_settings_context(self):
|
||||||
""" format settings strings """
|
""" format settings strings """
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -195,13 +195,14 @@ class Command(BaseCommand):
|
||||||
processes = %(processes)d
|
processes = %(processes)d
|
||||||
chmod-socket = 664
|
chmod-socket = 664
|
||||||
stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket
|
stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket
|
||||||
vacuum = true
|
|
||||||
uid = %(user)s
|
uid = %(user)s
|
||||||
gid = %(group)s
|
gid = %(group)s
|
||||||
env = HOME=%(home)s
|
env = HOME=%(home)s
|
||||||
touch-reload = %(project_dir)s/wsgi.py
|
touch-reload = %(project_dir)s/wsgi.py
|
||||||
enable-threads = true
|
vacuum = true # Remove socket stop
|
||||||
max-requests = 500
|
enable-threads = true # Initializes the GIL
|
||||||
|
max-requests = 500 # Mitigates memory leaks
|
||||||
|
lazy-apps = true # Don't share database connections
|
||||||
"""
|
"""
|
||||||
) % context
|
) % context
|
||||||
|
|
||||||
|
@ -220,11 +221,11 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
for extra_context in (nginx, uwsgi):
|
for extra_context in (nginx, uwsgi):
|
||||||
context.update(extra_context)
|
context.update(extra_context)
|
||||||
diff = run("echo '%(conf)s' | diff - %(file)s" % context, error_codes=[0,1,2])
|
diff = run("echo '%(conf)s' | diff - %(file)s" % context, valid_codes=(0,1,2))
|
||||||
if diff.return_code == 2:
|
if diff.exit_code == 2:
|
||||||
# File does not exist
|
# File does not exist
|
||||||
run("echo '%(conf)s' > %(file)s" % context, display=True)
|
run("echo '%(conf)s' > %(file)s" % context, display=True)
|
||||||
elif diff.return_code == 1:
|
elif diff.exit_code == 1:
|
||||||
# File is different, save the old one
|
# File is different, save the old one
|
||||||
if interactive:
|
if interactive:
|
||||||
msg = ("\n\nFile %(file)s be updated, do you like to overide "
|
msg = ("\n\nFile %(file)s be updated, do you like to overide "
|
||||||
|
@ -244,13 +245,13 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
if server_name:
|
if server_name:
|
||||||
run('ln -s /etc/nginx/sites-available/%(server_name)s.conf /etc/nginx/sites-enabled/' % context,
|
run('ln -s /etc/nginx/sites-available/%(server_name)s.conf /etc/nginx/sites-enabled/' % context,
|
||||||
error_codes=[0,1], display=True)
|
valid_codes=[0,1], display=True)
|
||||||
else:
|
else:
|
||||||
run('rm /etc/nginx/sites-enabled/default')
|
run('rm /etc/nginx/sites-enabled/default')
|
||||||
run('ln -s /etc/nginx/sites-available/%(project_name)s.conf /etc/nginx/sites-enabled/' % context,
|
run('ln -s /etc/nginx/sites-available/%(project_name)s.conf /etc/nginx/sites-enabled/' % context,
|
||||||
error_codes=[0,1], display=True)
|
valid_codes=[0,1], display=True)
|
||||||
run('ln -s /etc/uwsgi/apps-available/%(project_name)s.ini /etc/uwsgi/apps-enabled/' % context,
|
run('ln -s /etc/uwsgi/apps-available/%(project_name)s.ini /etc/uwsgi/apps-enabled/' % context,
|
||||||
error_codes=[0,1], display=True)
|
valid_codes=[0,1], display=True)
|
||||||
|
|
||||||
rotate = textwrap.dedent("""\
|
rotate = textwrap.dedent("""\
|
||||||
/var/log/nginx/*.log {
|
/var/log/nginx/*.log {
|
||||||
|
|
|
@ -223,7 +223,7 @@ password_query = \
|
||||||
run("chmod go= %(dovecot_dir)s/dovecot-sql.conf.ext" % context)
|
run("chmod go= %(dovecot_dir)s/dovecot-sql.conf.ext" % context)
|
||||||
|
|
||||||
file_name = "%(postfix_dir)s/master.cf" % context
|
file_name = "%(postfix_dir)s/master.cf" % context
|
||||||
grep_dovecot = run("grep dovecot %s" % file_name, error_codes=[0,1])
|
grep_dovecot = run("grep dovecot %s" % file_name, valid_codes=(0,1))
|
||||||
if grep_dovecot == '':
|
if grep_dovecot == '':
|
||||||
run("#Processing %s" % file_name)
|
run("#Processing %s" % file_name)
|
||||||
dovecot_master="""
|
dovecot_master="""
|
||||||
|
@ -264,8 +264,8 @@ amavis unix - - n - 5 smtp
|
||||||
|
|
||||||
|
|
||||||
#Postfix
|
#Postfix
|
||||||
mailname = run("cat /etc/mailname", error_codes=[0,1])
|
mailname = run("cat /etc/mailname", vallid_codes=[0,1])
|
||||||
hostname = run("hostname", error_codes=[0,1])
|
hostname = run("hostname", valid_codes=[0,1])
|
||||||
if mailname != hostname:
|
if mailname != hostname:
|
||||||
file_name = "/etc/mailname"
|
file_name = "/etc/mailname"
|
||||||
run("#Processing %s" % file_name)
|
run("#Processing %s" % file_name)
|
||||||
|
|
|
@ -40,11 +40,11 @@ class Command(BaseCommand):
|
||||||
'db_host': options.get('db_host'),
|
'db_host': options.get('db_host'),
|
||||||
'db_port': options.get('db_port') }
|
'db_port': options.get('db_port') }
|
||||||
|
|
||||||
run('su postgres -c "psql -c \\"CREATE USER %(db_user)s PASSWORD \'%(db_password)s\';\\""' % context, error_codes=[0,1])
|
run('su postgres -c "psql -c \\"CREATE USER %(db_user)s PASSWORD \'%(db_password)s\';\\""' % context, valid_codes=(0,1))
|
||||||
run('su postgres -c "psql -c \\"CREATE DATABASE %(db_name)s OWNER %(db_user)s;\\""' % context, error_codes=[0,1])
|
run('su postgres -c "psql -c \\"CREATE DATABASE %(db_name)s OWNER %(db_user)s;\\""' % context, valid_codes=(0,1))
|
||||||
context.update({'settings': os.path.join(get_project_dir(), 'settings.py')})
|
context.update({'settings': os.path.join(get_project_dir(), 'settings.py')})
|
||||||
|
|
||||||
if run("grep 'DATABASES' %(settings)s" % context, error_codes=[0,1]).return_code == 0:
|
if run("grep 'DATABASES' %(settings)s" % context, valid_codes=(0,1)).exit_code == 0:
|
||||||
# Update existing settings_file
|
# Update existing settings_file
|
||||||
run("sed -i \"s/'ENGINE': '\w*',/'ENGINE': 'django.db.backends.postgresql_psycopg2',/\" %(settings)s" % context)
|
run("sed -i \"s/'ENGINE': '\w*',/'ENGINE': 'django.db.backends.postgresql_psycopg2',/\" %(settings)s" % context)
|
||||||
run("sed -i \"s/'NAME': '.*',/'NAME': '%(db_name)s',/\" %(settings)s" % context)
|
run("sed -i \"s/'NAME': '.*',/'NAME': '%(db_name)s',/\" %(settings)s" % context)
|
||||||
|
|
|
@ -11,9 +11,9 @@ def run_tuple(services, action, options, optional=False):
|
||||||
services = [services]
|
services = [services]
|
||||||
for service in services:
|
for service in services:
|
||||||
if options.get(service):
|
if options.get(service):
|
||||||
error_codes = [0,1] if optional else [0]
|
valid_codes = (0,1) if optional else (0,)
|
||||||
e = run('service %s %s' % (service, action), error_codes=error_codes)
|
e = run('service %s %s' % (service, action), valid_codes=valid_codes)
|
||||||
if e.return_code == 1:
|
if e.exit_code == 1:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ r = functools.partial(run, silent=False)
|
||||||
|
|
||||||
def get_existing_pip_installation():
|
def get_existing_pip_installation():
|
||||||
""" returns current pip installation path """
|
""" returns current pip installation path """
|
||||||
if run("pip freeze|grep django-orchestra", error_codes=[0,1]).return_code == 0:
|
if run("pip freeze|grep django-orchestra", valid_codes=(0,1)).exit_code == 0:
|
||||||
for lib_path in get_python_lib(), get_python_lib(prefix="/usr/local"):
|
for lib_path in get_python_lib(), get_python_lib(prefix="/usr/local"):
|
||||||
existing_path = os.path.abspath(os.path.join(lib_path, "orchestra"))
|
existing_path = os.path.abspath(os.path.join(lib_path, "orchestra"))
|
||||||
if os.path.exists(existing_path):
|
if os.path.exists(existing_path):
|
||||||
|
|
|
@ -93,16 +93,16 @@ def runiterator(command, display=False, stdin=b''):
|
||||||
|
|
||||||
state = _Attribute(stdout)
|
state = _Attribute(stdout)
|
||||||
state.stderr = stderr
|
state.stderr = stderr
|
||||||
state.return_code = p.poll()
|
state.exit_code = p.poll()
|
||||||
state.command = command
|
state.command = command
|
||||||
yield state
|
yield state
|
||||||
|
|
||||||
if state.return_code != None:
|
if state.exit_code != None:
|
||||||
p.stdout.close()
|
p.stdout.close()
|
||||||
p.stderr.close()
|
p.stderr.close()
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
def join(iterator, display=False, silent=False, error_codes=[0]):
|
def join(iterator, display=False, silent=False, valid_codes=(0,)):
|
||||||
""" joins the iterator process """
|
""" joins the iterator process """
|
||||||
stdout = b''
|
stdout = b''
|
||||||
stderr = b''
|
stderr = b''
|
||||||
|
@ -110,18 +110,18 @@ def join(iterator, display=False, silent=False, error_codes=[0]):
|
||||||
stdout += state.stdout
|
stdout += state.stdout
|
||||||
stderr += state.stderr
|
stderr += state.stderr
|
||||||
|
|
||||||
return_code = state.return_code
|
exit_code = state.exit_code
|
||||||
|
|
||||||
out = _Attribute(stdout.strip())
|
out = _Attribute(stdout.strip())
|
||||||
err = stderr.strip()
|
err = stderr.strip()
|
||||||
|
|
||||||
out.failed = False
|
out.failed = False
|
||||||
out.return_code = return_code
|
out.exit_code = exit_code
|
||||||
out.stderr = err
|
out.stderr = err
|
||||||
if return_code not in error_codes:
|
if exit_code not in valid_codes:
|
||||||
out.failed = True
|
out.failed = True
|
||||||
msg = "\nrun() encountered an error (return code %s) while executing '%s'\n"
|
msg = "\nrun() encountered an error (return code %s) while executing '%s'\n"
|
||||||
msg = msg % (return_code, state.command)
|
msg = msg % (exit_code, state.command)
|
||||||
if display:
|
if display:
|
||||||
sys.stderr.write("\n\033[1;31mCommandError: %s %s\033[m\n" % (msg, err))
|
sys.stderr.write("\n\033[1;31mCommandError: %s %s\033[m\n" % (msg, err))
|
||||||
if not silent:
|
if not silent:
|
||||||
|
@ -131,12 +131,12 @@ def join(iterator, display=False, silent=False, error_codes=[0]):
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def run(command, display=False, error_codes=[0], silent=False, stdin=b'', async=False):
|
def run(command, display=False, valid_codes=(0,), silent=False, stdin=b'', async=False):
|
||||||
iterator = runiterator(command, display, stdin)
|
iterator = runiterator(command, display, stdin)
|
||||||
next(iterator)
|
next(iterator)
|
||||||
if async:
|
if async:
|
||||||
return iterator
|
return iterator
|
||||||
return join(iterator, display=display, silent=silent, error_codes=error_codes)
|
return join(iterator, display=display, silent=silent, valid_codes=valie_codes)
|
||||||
|
|
||||||
|
|
||||||
def sshrun(addr, command, *args, **kwargs):
|
def sshrun(addr, command, *args, **kwargs):
|
||||||
|
|
Loading…
Reference in a new issue