Improved db indexes
This commit is contained in:
parent
4301d76011
commit
ebd5ff03ce
2
TODO.md
2
TODO.md
|
@ -461,6 +461,6 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
||||||
# TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects
|
# TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects
|
||||||
|
|
||||||
|
|
||||||
|
# INDEXES for most used queries: account FK
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ def admin_link(*args, **kwargs):
|
||||||
return '---'
|
return '---'
|
||||||
display = kwargs.get('display')
|
display = kwargs.get('display')
|
||||||
if display:
|
if display:
|
||||||
display = getattr(obj, display, None)
|
display = getattr(obj, display, display)
|
||||||
else:
|
else:
|
||||||
display = obj
|
display = obj
|
||||||
try:
|
try:
|
||||||
|
@ -123,7 +123,8 @@ def admin_link(*args, **kwargs):
|
||||||
extra = ''
|
extra = ''
|
||||||
if kwargs['popup']:
|
if kwargs['popup']:
|
||||||
extra = 'onclick="return showAddAnotherPopup(this);"'
|
extra = 'onclick="return showAddAnotherPopup(this);"'
|
||||||
return mark_safe('<a href="%s" %s>%s</a>' % (url, extra, display))
|
title = "Change %s" % obj._meta.verbose_name
|
||||||
|
return mark_safe('<a href="%s" title="%s" %s>%s</a>' % (url, title, extra, display))
|
||||||
|
|
||||||
|
|
||||||
@admin_field
|
@admin_field
|
||||||
|
|
|
@ -16,7 +16,7 @@ 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
|
||||||
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
|
||||||
from orchestra.core import services, accounts
|
from orchestra.core import services, accounts
|
||||||
from orchestra.forms import UserChangeForm
|
from orchestra.forms import UserChangeForm
|
||||||
|
|
||||||
|
@ -189,8 +189,7 @@ class AccountAdminMixin(object):
|
||||||
|
|
||||||
def account_link(self, instance):
|
def account_link(self, instance):
|
||||||
account = instance.account if instance.pk else self.account
|
account = instance.account if instance.pk else self.account
|
||||||
url = change_url(account)
|
return admin_link()(account)
|
||||||
return '<a href="%s">%s</a>' % (url, account)
|
|
||||||
account_link.short_description = _("account")
|
account_link.short_description = _("account")
|
||||||
account_link.allow_tags = True
|
account_link.allow_tags = True
|
||||||
account_link.admin_order_field = 'account__username'
|
account_link.admin_order_field = 'account__username'
|
||||||
|
|
|
@ -85,7 +85,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
for website in websites:
|
for website in websites:
|
||||||
site_link = get_on_site_link(website.get_absolute_url())
|
site_link = get_on_site_link(website.get_absolute_url())
|
||||||
admin_url = change_url(website)
|
admin_url = change_url(website)
|
||||||
link = '<a href="%s">%s %s</a>' % (admin_url, website.name, site_link)
|
title = _("Edit website")
|
||||||
|
link = '<a href="%s" title="%s">%s %s</a>' % (
|
||||||
|
admin_url, title, website.name, site_link)
|
||||||
links.append(link)
|
links.append(link)
|
||||||
return '<br>'.join(links)
|
return '<br>'.join(links)
|
||||||
site_link = get_on_site_link('http://%s' % domain.name)
|
site_link = get_on_site_link('http://%s' % domain.name)
|
||||||
|
@ -127,7 +129,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
structured_name=Concat('top__name', 'name')
|
structured_name=Concat('top__name', 'name')
|
||||||
).order_by('-structured_id', 'structured_name')
|
).order_by('-structured_id', 'structured_name')
|
||||||
if apps.isinstalled('orchestra.contrib.websites'):
|
if apps.isinstalled('orchestra.contrib.websites'):
|
||||||
qs = qs.prefetch_related('websites')
|
qs = qs.prefetch_related('websites__domains')
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import orchestra.contrib.domains.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('domains', '0004_auto_20150720_1121'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='domain',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=256, validators=[orchestra.contrib.domains.validators.validate_domain_name, orchestra.contrib.domains.validators.validate_allowed_domain], db_index=True, verbose_name='name', unique=True, help_text='Domain or subdomain name.'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='domain',
|
||||||
|
name='top',
|
||||||
|
field=models.ForeignKey(editable=False, verbose_name='top domain', related_name='subdomain_set', to='domains.Domain', null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='record',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(max_length=32, verbose_name='type', choices=[('MX', 'MX'), ('NS', 'NS'), ('CNAME', 'CNAME'), ('A', 'A (IPv4 address)'), ('AAAA', 'AAAA (IPv6 address)'), ('SRV', 'SRV'), ('TXT', 'TXT'), ('SPF', 'SPF'), ('SOA', 'SOA')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -24,7 +24,7 @@ class DomainQuerySet(models.QuerySet):
|
||||||
|
|
||||||
|
|
||||||
class Domain(models.Model):
|
class Domain(models.Model):
|
||||||
name = models.CharField(_("name"), max_length=256, unique=True,
|
name = models.CharField(_("name"), max_length=256, unique=True, db_index=True,
|
||||||
help_text=_("Domain or subdomain name."),
|
help_text=_("Domain or subdomain name."),
|
||||||
validators=[
|
validators=[
|
||||||
validators.validate_domain_name,
|
validators.validate_domain_name,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.core.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mailboxes', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='mailbox',
|
||||||
|
name='filtering',
|
||||||
|
field=models.CharField(max_length=16, choices=[('CUSTOM', 'Custom filtering'), ('DISABLE', 'Disable'), ('REDIRECT', 'Archive spam (Score≥8)'), ('REDIRECT5', 'Archive spam (Score≥5)'), ('REJECT', 'Reject spam (Score≥8)'), ('REJECT5', 'Reject spam (Score≥5)')], default='REDIRECT'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='mailbox',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=64, db_index=True, unique=True, help_text='Required. 32 characters or fewer. Letters, digits and ./-/_ only.', validators=[django.core.validators.RegexValidator('^[\\w.-]+$', 'Enter a valid mailbox name.')], verbose_name='name'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -14,7 +14,7 @@ from . import validators, settings
|
||||||
class Mailbox(models.Model):
|
class Mailbox(models.Model):
|
||||||
CUSTOM = 'CUSTOM'
|
CUSTOM = 'CUSTOM'
|
||||||
|
|
||||||
name = models.CharField(_("name"), max_length=64, unique=True,
|
name = models.CharField(_("name"), max_length=64, unique=True, db_index=True,
|
||||||
help_text=_("Required. %s characters or fewer. Letters, digits and ./-/_ only.") %
|
help_text=_("Required. %s characters or fewer. Letters, digits and ./-/_ only.") %
|
||||||
settings.MAILBOXES_NAME_MAX_LENGTH,
|
settings.MAILBOXES_NAME_MAX_LENGTH,
|
||||||
validators=[
|
validators=[
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mailer', '0004_auto_20150805_1328'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='message',
|
||||||
|
name='last_try',
|
||||||
|
field=models.DateTimeField(null=True, db_index=True, verbose_name='last try'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='message',
|
||||||
|
name='priority',
|
||||||
|
field=models.PositiveIntegerField(default=2, choices=[(0, 'Critical (not queued)'), (1, 'High'), (2, 'Normal'), (3, 'Low')], db_index=True, verbose_name='Priority'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='message',
|
||||||
|
name='retries',
|
||||||
|
field=models.PositiveIntegerField(default=0, db_index=True, verbose_name='retries'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='message',
|
||||||
|
name='state',
|
||||||
|
field=models.CharField(default='QUEUED', choices=[('QUEUED', 'Queued'), ('SENT', 'Sent'), ('DEFERRED', 'Deferred'), ('FAILED', 'Failed')], db_index=True, max_length=16, verbose_name='State'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -27,15 +27,17 @@ class Message(models.Model):
|
||||||
(LOW, _("Low")),
|
(LOW, _("Low")),
|
||||||
)
|
)
|
||||||
|
|
||||||
state = models.CharField(_("State"), max_length=16, choices=STATES, default=QUEUED)
|
state = models.CharField(_("State"), max_length=16, choices=STATES, default=QUEUED,
|
||||||
priority = models.PositiveIntegerField(_("Priority"), choices=PRIORITIES, default=NORMAL)
|
db_index=True)
|
||||||
|
priority = models.PositiveIntegerField(_("Priority"), choices=PRIORITIES, default=NORMAL,
|
||||||
|
db_index=True)
|
||||||
to_address = models.CharField(max_length=256)
|
to_address = models.CharField(max_length=256)
|
||||||
from_address = models.CharField(max_length=256)
|
from_address = models.CharField(max_length=256)
|
||||||
subject = models.TextField(_("subject"))
|
subject = models.TextField(_("subject"))
|
||||||
content = models.TextField(_("content"))
|
content = models.TextField(_("content"))
|
||||||
created_at = models.DateTimeField(_("created at"), auto_now_add=True)
|
created_at = models.DateTimeField(_("created at"), auto_now_add=True)
|
||||||
retries = models.PositiveIntegerField(_("retries"), default=0)
|
retries = models.PositiveIntegerField(_("retries"), default=0, db_index=True)
|
||||||
last_try = models.DateTimeField(_("last try"), null=True)
|
last_try = models.DateTimeField(_("last try"), null=True, db_index=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s to %s' % (self.subject, self.to_address)
|
return '%s to %s' % (self.subject, self.to_address)
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import orchestra.core.validators
|
||||||
|
import orchestra.models.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orchestration', '0005_auto_20150709_1016'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='route',
|
||||||
|
name='backend',
|
||||||
|
field=models.CharField(choices=[('Apache2Traffic', '[M] Apache 2 Traffic'), ('ApacheTrafficByName', '[M] ApacheTrafficByName'), ('DokuWikiMuTraffic', '[M] DokuWiki MU Traffic'), ('DovecotMaildirDisk', '[M] Dovecot Maildir size'), ('Exim4Traffic', '[M] Exim4 traffic'), ('MailmanSubscribers', '[M] Mailman subscribers'), ('MailmanTraffic', '[M] Mailman traffic'), ('MysqlDisk', '[M] MySQL disk'), ('OpenVZTraffic', '[M] OpenVZTraffic'), ('PostfixMailscannerTraffic', '[M] Postfix-Mailscanner traffic'), ('UNIXUserDisk', '[M] UNIX user disk'), ('VsFTPdTraffic', '[M] VsFTPd traffic'), ('WordpressMuTraffic', '[M] Wordpress MU Traffic'), ('OwnCloudDiskQuota', '[M] ownCloud SaaS Disk Quota'), ('OwncloudTraffic', '[M] ownCloud SaaS Traffic'), ('PhpListTraffic', '[M] phpList SaaS Traffic'), ('Apache2Backend', '[S] Apache 2'), ('BSCWBackend', '[S] BSCW SaaS'), ('Bind9MasterDomainBackend', '[S] Bind9 master domain'), ('Bind9SlaveDomainBackend', '[S] Bind9 slave domain'), ('DokuWikiMuBackend', '[S] DokuWiki multisite'), ('DrupalMuBackend', '[S] Drupal multisite'), ('GitLabSaaSBackend', '[S] GitLab SaaS'), ('AutoresponseBackend', '[S] Mail autoresponse'), ('MailScannerSpamRuleBackend', '[S] MailScanner ruleset'), ('MailmanBackend', '[S] Mailman'), ('MailmanVirtualDomainBackend', '[S] Mailman virtdomain-only'), ('MoodleBackend', '[S] Moodle'), ('MoodleWWWRootBackend', '[S] Moodle WWWRoot (required)'), ('MoodleMuBackend', '[S] Moodle multisite'), ('MySQLBackend', '[S] MySQL database'), ('MySQLUserBackend', '[S] MySQL user'), ('PHPBackend', '[S] PHP FPM/FCGID'), ('PangeaProxmoxOVZ', '[S] PangeaProxmoxOVZ'), ('PostfixAddressBackend', '[S] Postfix address'), ('PostfixAddressVirtualDomainBackend', '[S] Postfix address virtdomain-only'), ('PostfixRecipientAccessBackend', '[S] Postfix recipient access'), ('ProxmoxOVZ', '[S] ProxmoxOVZ'), ('uWSGIPythonBackend', '[S] Python uWSGI'), ('StaticBackend', '[S] Static'), ('SymbolicLinkBackend', '[S] Symbolic link webapp'), ('SyncBind9MasterDomainBackend', '[S] Sync Bind9 master domain'), ('SyncBind9SlaveDomainBackend', '[S] Sync Bind9 slave domain'), ('UNIXUserMaildirBackend', '[S] UNIX maildir user'), ('UNIXUserBackend', '[S] UNIX user'), ('WebalizerAppBackend', '[S] Webalizer App'), ('WebalizerBackend', '[S] Webalizer Content'), ('WordPressURLBackend', '[S] WordPress URL'), ('WordPressBackend', '[S] Wordpress'), ('WordpressMuBackend', '[S] Wordpress multisite'), ('OwnCloudBackend', '[S] ownCloud SaaS'), ('PhpListSaaSBackend', '[S] phpList SaaS')], max_length=256, verbose_name='backend'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='server',
|
||||||
|
name='address',
|
||||||
|
field=orchestra.models.fields.NullableCharField(help_text='Optional IP address or domain name. If blank, name field will be used for address resolution.<br>If the IP address never changes you can set this field and save DNS requests.', verbose_name='address', validators=[orchestra.core.validators.OrValidator(orchestra.core.validators.validate_ip_address, orchestra.core.validators.validate_hostname)], blank=True, max_length=256, unique=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='server',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(help_text='Verbose name or hostname of this server.', max_length=256, verbose_name='name', unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterIndexTogether(
|
||||||
|
name='backendoperation',
|
||||||
|
index_together=set([('content_type', 'object_id')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -148,6 +148,9 @@ class BackendOperation(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Operation")
|
verbose_name = _("Operation")
|
||||||
verbose_name_plural = _("Operations")
|
verbose_name_plural = _("Operations")
|
||||||
|
index_together = (
|
||||||
|
('content_type', 'object_id'),
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s.%s(%s)' % (self.backend, self.action, self.instance or self.instance_repr)
|
return '%s.%s(%s)' % (self.backend, self.action, self.instance or self.instance_repr)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0004_auto_20150729_0945'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='billed_metric',
|
||||||
|
field=models.DecimalField(decimal_places=2, null=True, verbose_name='billed metric', blank=True, max_digits=16),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='order',
|
||||||
|
name='content_object_repr',
|
||||||
|
field=models.CharField(max_length=256, verbose_name='content object representation', help_text='Used for searches.', editable=False),
|
||||||
|
),
|
||||||
|
migrations.AlterIndexTogether(
|
||||||
|
name='order',
|
||||||
|
index_together=set([('content_type', 'object_id')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -172,6 +172,9 @@ class Order(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = 'id'
|
get_latest_by = 'id'
|
||||||
|
index_together = (
|
||||||
|
('content_type', 'object_id'),
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.service)
|
return str(self.service)
|
||||||
|
|
|
@ -134,6 +134,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
list_display = ('id', 'file_url', 'display_transactions', 'created_at')
|
list_display = ('id', 'file_url', 'display_transactions', 'created_at')
|
||||||
fields = ('data', 'file_url', 'created_at')
|
fields = ('data', 'file_url', 'created_at')
|
||||||
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
|
readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at')
|
||||||
|
list_prefetch_related = ('transactions',)
|
||||||
inlines = [TransactionInline]
|
inlines = [TransactionInline]
|
||||||
change_view_actions = (
|
change_view_actions = (
|
||||||
actions.mark_process_as_executed, actions.abort, actions.commit, actions.report
|
actions.mark_process_as_executed, actions.abort, actions.commit, actions.report
|
||||||
|
@ -150,8 +151,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
ids = []
|
ids = []
|
||||||
lines = []
|
lines = []
|
||||||
counter = 0
|
counter = 0
|
||||||
# Because of values_list this query doesn't benefit from prefetch_related
|
for trans in process.transactions.all():
|
||||||
for trans in process.transactions.only('id', 'state'):
|
|
||||||
color = STATE_COLORS.get(trans.state, 'black')
|
color = STATE_COLORS.get(trans.state, 'black')
|
||||||
state = trans.get_state_display()
|
state = trans.get_state_display()
|
||||||
ids.append('<span style="color:%s" title="%s">%i</span>' % (color, state, trans.id))
|
ids.append('<span style="color:%s" title="%s">%i</span>' % (color, state, trans.id))
|
||||||
|
@ -163,7 +163,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
lines.append(','.join(ids))
|
lines.append(','.join(ids))
|
||||||
transactions = '<br'.join(lines)
|
transactions = '<br'.join(lines)
|
||||||
url = reverse('admin:payments_transaction_changelist')
|
url = reverse('admin:payments_transaction_changelist')
|
||||||
url += '?processes=%i' % process.id
|
url += '?process_id=%i' % process.id
|
||||||
return '<a href="%s">%s</a>' % (url, transactions)
|
return '<a href="%s">%s</a>' % (url, transactions)
|
||||||
display_transactions.short_description = _("Transactions")
|
display_transactions.short_description = _("Transactions")
|
||||||
display_transactions.allow_tags = True
|
display_transactions.allow_tags = True
|
||||||
|
@ -172,7 +172,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_change_view_actions(self, obj=None):
|
def get_change_view_actions(self, obj=None):
|
||||||
actions = super(TransactionProcessAdmin, self).get_change_view_actions()
|
actions = super().get_change_view_actions()
|
||||||
exclude = []
|
exclude = []
|
||||||
if obj:
|
if obj:
|
||||||
if obj.state == TransactionProcess.EXECUTED:
|
if obj.state == TransactionProcess.EXECUTED:
|
||||||
|
@ -186,13 +186,11 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
def delete_view(self, request, object_id, extra_context=None):
|
def delete_view(self, request, object_id, extra_context=None):
|
||||||
queryset = self.model.objects.filter(id=object_id)
|
queryset = self.model.objects.filter(id=object_id)
|
||||||
related_transactions = helpers.pre_delete_processes(self, request, queryset)
|
related_transactions = helpers.pre_delete_processes(self, request, queryset)
|
||||||
response = super(TransactionProcessAdmin, self).delete_view(
|
response = super().delete_view(request, object_id, extra_context)
|
||||||
request, object_id, extra_context)
|
|
||||||
if isinstance(response, HttpResponseRedirect):
|
if isinstance(response, HttpResponseRedirect):
|
||||||
helpers.post_delete_processes(self, request, related_transactions)
|
helpers.post_delete_processes(self, request, related_transactions)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(PaymentSource, PaymentSourceAdmin)
|
admin.site.register(PaymentSource, PaymentSourceAdmin)
|
||||||
admin.site.register(Transaction, TransactionAdmin)
|
admin.site.register(Transaction, TransactionAdmin)
|
||||||
admin.site.register(TransactionProcess, TransactionProcessAdmin)
|
admin.site.register(TransactionProcess, TransactionProcessAdmin)
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import orchestra.models.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('resources', '0009_auto_20150804_1450'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='monitordata',
|
||||||
|
name='monitor',
|
||||||
|
field=models.CharField(db_index=True, choices=[('Apache2Traffic', '[M] Apache 2 Traffic'), ('ApacheTrafficByName', '[M] ApacheTrafficByName'), ('DokuWikiMuTraffic', '[M] DokuWiki MU Traffic'), ('DovecotMaildirDisk', '[M] Dovecot Maildir size'), ('Exim4Traffic', '[M] Exim4 traffic'), ('MailmanSubscribers', '[M] Mailman subscribers'), ('MailmanTraffic', '[M] Mailman traffic'), ('MysqlDisk', '[M] MySQL disk'), ('OpenVZTraffic', '[M] OpenVZTraffic'), ('PostfixMailscannerTraffic', '[M] Postfix-Mailscanner traffic'), ('UNIXUserDisk', '[M] UNIX user disk'), ('VsFTPdTraffic', '[M] VsFTPd traffic'), ('WordpressMuTraffic', '[M] Wordpress MU Traffic'), ('OwnCloudDiskQuota', '[M] ownCloud SaaS Disk Quota'), ('OwncloudTraffic', '[M] ownCloud SaaS Traffic'), ('PhpListTraffic', '[M] phpList SaaS Traffic')], verbose_name='monitor', max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='monitordata',
|
||||||
|
name='object_id',
|
||||||
|
field=models.PositiveIntegerField(verbose_name='object id'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='resource',
|
||||||
|
name='disable_trigger',
|
||||||
|
field=models.BooleanField(help_text='Disables monitors exeeded and recovery triggers', verbose_name='disable trigger', default=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='resource',
|
||||||
|
name='monitors',
|
||||||
|
field=orchestra.models.fields.MultiSelectField(help_text='Monitor backends used for monitoring this resource.', blank=True, verbose_name='monitors', max_length=256, choices=[('Apache2Traffic', '[M] Apache 2 Traffic'), ('ApacheTrafficByName', '[M] ApacheTrafficByName'), ('DokuWikiMuTraffic', '[M] DokuWiki MU Traffic'), ('DovecotMaildirDisk', '[M] Dovecot Maildir size'), ('Exim4Traffic', '[M] Exim4 traffic'), ('MailmanSubscribers', '[M] Mailman subscribers'), ('MailmanTraffic', '[M] Mailman traffic'), ('MysqlDisk', '[M] MySQL disk'), ('OpenVZTraffic', '[M] OpenVZTraffic'), ('PostfixMailscannerTraffic', '[M] Postfix-Mailscanner traffic'), ('UNIXUserDisk', '[M] UNIX user disk'), ('VsFTPdTraffic', '[M] VsFTPd traffic'), ('WordpressMuTraffic', '[M] Wordpress MU Traffic'), ('OwnCloudDiskQuota', '[M] ownCloud SaaS Disk Quota'), ('OwncloudTraffic', '[M] ownCloud SaaS Traffic'), ('PhpListTraffic', '[M] phpList SaaS Traffic')]),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='resourcedata',
|
||||||
|
name='object_id',
|
||||||
|
field=models.PositiveIntegerField(verbose_name='object id'),
|
||||||
|
),
|
||||||
|
migrations.AlterIndexTogether(
|
||||||
|
name='monitordata',
|
||||||
|
index_together=set([('content_type', 'object_id')]),
|
||||||
|
),
|
||||||
|
migrations.AlterIndexTogether(
|
||||||
|
name='resourcedata',
|
||||||
|
index_together=set([('content_type', 'object_id')]),
|
||||||
|
),
|
||||||
|
]
|
|
@ -179,8 +179,8 @@ class ResourceDataQuerySet(models.QuerySet):
|
||||||
class ResourceData(models.Model):
|
class ResourceData(models.Model):
|
||||||
""" Stores computed resource usage and allocation """
|
""" Stores computed resource usage and allocation """
|
||||||
resource = models.ForeignKey(Resource, related_name='dataset', verbose_name=_("resource"))
|
resource = models.ForeignKey(Resource, related_name='dataset', verbose_name=_("resource"))
|
||||||
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"), db_index=True)
|
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"))
|
||||||
object_id = models.PositiveIntegerField(_("object id"), db_index=True)
|
object_id = models.PositiveIntegerField(_("object id"))
|
||||||
used = models.DecimalField(_("used"), max_digits=16, decimal_places=3, null=True,
|
used = models.DecimalField(_("used"), max_digits=16, decimal_places=3, null=True,
|
||||||
editable=False)
|
editable=False)
|
||||||
updated_at = models.DateTimeField(_("updated"), null=True, editable=False)
|
updated_at = models.DateTimeField(_("updated"), null=True, editable=False)
|
||||||
|
@ -194,6 +194,9 @@ class ResourceData(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('resource', 'content_type', 'object_id')
|
unique_together = ('resource', 'content_type', 'object_id')
|
||||||
verbose_name_plural = _("resource data")
|
verbose_name_plural = _("resource data")
|
||||||
|
index_together = (
|
||||||
|
('content_type', 'object_id'),
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: %s" % (self.resource, self.content_object)
|
return "%s: %s" % (self.resource, self.content_object)
|
||||||
|
@ -264,8 +267,8 @@ class MonitorData(models.Model):
|
||||||
""" Stores monitored data """
|
""" Stores monitored data """
|
||||||
monitor = models.CharField(_("monitor"), max_length=256, db_index=True,
|
monitor = models.CharField(_("monitor"), max_length=256, db_index=True,
|
||||||
choices=ServiceMonitor.get_choices())
|
choices=ServiceMonitor.get_choices())
|
||||||
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"), db_index=True)
|
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"))
|
||||||
object_id = models.PositiveIntegerField(_("object id"), db_index=True)
|
object_id = models.PositiveIntegerField(_("object id"))
|
||||||
created_at = models.DateTimeField(_("created"), default=timezone.now, db_index=True)
|
created_at = models.DateTimeField(_("created"), default=timezone.now, db_index=True)
|
||||||
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
|
value = models.DecimalField(_("value"), max_digits=16, decimal_places=2)
|
||||||
state = models.DecimalField(_("state"), max_digits=16, decimal_places=2, null=True,
|
state = models.DecimalField(_("state"), max_digits=16, decimal_places=2, null=True,
|
||||||
|
@ -279,6 +282,9 @@ class MonitorData(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
get_latest_by = 'id'
|
get_latest_by = 'id'
|
||||||
verbose_name_plural = _("monitor data")
|
verbose_name_plural = _("monitor data")
|
||||||
|
index_together = (
|
||||||
|
('content_type', 'object_id'),
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.monitor)
|
return str(self.monitor)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.encoding import force_text
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import change_url, get_modeladmin
|
from orchestra.admin.utils import admin_link, get_modeladmin
|
||||||
from orchestra.contrib.accounts.actions import list_accounts
|
from orchestra.contrib.accounts.actions import list_accounts
|
||||||
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
from orchestra.contrib.accounts.admin import AccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
@ -72,9 +72,8 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
site_url = content.get_absolute_url()
|
site_url = content.get_absolute_url()
|
||||||
site_link = get_on_site_link(site_url)
|
site_link = get_on_site_link(site_url)
|
||||||
website = content.website
|
website = content.website
|
||||||
admin_url = change_url(website)
|
name = "%s on %s %s" % (website.name, content.path, site_link)
|
||||||
name = "%s on %s" % (website.name, content.path)
|
link = admin_link(display=name)(website)
|
||||||
link = '<a href="%s">%s %s</a>' % (admin_url, name, site_link)
|
|
||||||
websites.append(link)
|
websites.append(link)
|
||||||
if not websites:
|
if not websites:
|
||||||
add_url = reverse('admin:websites_website_add')
|
add_url = reverse('admin:websites_website_add')
|
||||||
|
|
|
@ -87,7 +87,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
for content in website.content_set.all():
|
for content in website.content_set.all():
|
||||||
site_link = get_on_site_link(content.get_absolute_url())
|
site_link = get_on_site_link(content.get_absolute_url())
|
||||||
webapp = content.webapp
|
webapp = content.webapp
|
||||||
detail = webapp.get_type_display()
|
detail = _("Edit Webapp") + ' ' + webapp.get_type_display()
|
||||||
try:
|
try:
|
||||||
detail += ' ' + webapp.type_instance.get_detail()
|
detail += ' ' + webapp.type_instance.get_detail()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -55,15 +55,18 @@ class Apache2Backend(ServiceController):
|
||||||
return '\n'.join([conf for location, conf in extra_conf])
|
return '\n'.join([conf for location, conf in extra_conf])
|
||||||
|
|
||||||
def render_virtual_host(self, site, context, ssl=False):
|
def render_virtual_host(self, site, context, ssl=False):
|
||||||
context['port'] = self.HTTPS_PORT if ssl else self.HTTP_PORT
|
context.update({
|
||||||
context['vhost_set_fcgid'] = False
|
'port': self.HTTPS_PORT if ssl else self.HTTP_PORT,
|
||||||
|
'vhost_set_fcgid': False,
|
||||||
|
'server_alias_lines': ' \\\n '.join(context['server_alias'])
|
||||||
|
})
|
||||||
context['extra_conf'] = self.get_extra_conf(site, context, ssl)
|
context['extra_conf'] = self.get_extra_conf(site, context, ssl)
|
||||||
return Template(textwrap.dedent("""\
|
return Template(textwrap.dedent("""\
|
||||||
<VirtualHost{% for ip in ips %} {{ ip }}:{{ port }}{% endfor %}>
|
<VirtualHost{% for ip in ips %} {{ ip }}:{{ port }}{% endfor %}>
|
||||||
IncludeOptional /etc/apache2/site[s]-override/{{ site_unique_name }}.con[f]
|
IncludeOptional /etc/apache2/site[s]-override/{{ site_unique_name }}.con[f]
|
||||||
ServerName {{ server_name }}\
|
ServerName {{ server_name }}\
|
||||||
{% if server_alias %}
|
{% if server_alias %}
|
||||||
ServerAlias {{ server_alias|join:' ' }}{% endif %}\
|
ServerAlias {{ server_alias_lines }}{% endif %}\
|
||||||
{% if access_log %}
|
{% if access_log %}
|
||||||
CustomLog {{ access_log }} common{% endif %}\
|
CustomLog {{ access_log }} common{% endif %}\
|
||||||
{% if error_log %}
|
{% if error_log %}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('websites', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='website',
|
||||||
|
name='domains',
|
||||||
|
field=models.ManyToManyField(to='domains.Domain', related_name='websites', verbose_name='domains', blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='websitedirective',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(choices=[(None, '-------'), ('HTTPD', [('redirect', 'Redirection'), ('proxy', 'Proxy'), ('error-document', 'ErrorDocumentRoot')]), ('SaaS', [('wordpress-saas', 'WordPress SaaS'), ('dokuwiki-saas', 'DokuWiki SaaS'), ('drupal-saas', 'Drupdal SaaS'), ('moodle-saas', 'Moodle SaaS')]), ('ModSecurity', [('sec-rule-remove', 'SecRuleRemoveById'), ('sec-engine', 'SecRuleEngine Off')]), ('SSL', [('ssl-ca', 'SSL CA'), ('ssl-cert', 'SSL cert'), ('ssl-key', 'SSL key')])], db_index=True, verbose_name='name', max_length=128),
|
||||||
|
),
|
||||||
|
]
|
|
@ -115,7 +115,7 @@ class Website(models.Model):
|
||||||
class WebsiteDirective(models.Model):
|
class WebsiteDirective(models.Model):
|
||||||
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
||||||
related_name='directives')
|
related_name='directives')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128, db_index=True,
|
||||||
choices=SiteDirective.get_choices())
|
choices=SiteDirective.get_choices())
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from ipaddress import ip_address
|
||||||
import phonenumbers
|
import phonenumbers
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.deconstruct import deconstructible
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from ..utils.python import import_class
|
from ..utils.python import import_class
|
||||||
|
@ -37,6 +38,7 @@ def all_valid(*args):
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
||||||
|
|
||||||
|
@deconstructible
|
||||||
class OrValidator(object):
|
class OrValidator(object):
|
||||||
"""
|
"""
|
||||||
Run validators with an OR logic
|
Run validators with an OR logic
|
||||||
|
|
Loading…
Reference in a new issue