Added SOA settings for domains
This commit is contained in:
parent
74f72ed8a1
commit
caa087deb6
38
TODO.md
38
TODO.md
|
@ -13,11 +13,6 @@
|
|||
|
||||
* backend logs with hal logo
|
||||
|
||||
# LAST version of this shit http://wkhtmltopdf.org/downloads.h otml
|
||||
#apt-get install xfonts-75dpi
|
||||
#wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2.1/wkhtmltox-0.12.2.1_linux-jessie-amd64.deb
|
||||
#dpkg -i wkhtmltox-0.12.2.1_linux-jessie-amd64.deb
|
||||
|
||||
* help_text on readonly_fields specialy Bill.state. (eg. A bill is in OPEN state when bla bla )
|
||||
|
||||
* create log file at /var/log/orchestra.log and rotate
|
||||
|
@ -175,9 +170,6 @@ require_once(‘/etc/moodles/’.$moodle_host.‘config.php’);``` moodle/drupl
|
|||
* Autocomplete admin fields like <site_name>.phplist... with js
|
||||
|
||||
* allow empty metric pack for default rates? changes on rating algo
|
||||
# don't produce lines with cost == 0 or quantity 0 ? maybe minimal quantity for billing? like 0.1 ? or minimal price? per line or per bill?
|
||||
|
||||
# lines too long on invoice, double lines or cut
|
||||
|
||||
* payment methods icons
|
||||
* use server.name | server.address on python backends, like gitlab instead of settings?
|
||||
|
@ -373,23 +365,10 @@ method(
|
|||
arg, arg, arg)
|
||||
|
||||
|
||||
# dovecot sieve only allolws one fucking active script. refactor mailbox shit to replace active script symlink by orchestra. Create a generic wrapper that includes al filters (rc, imp and orchestra)
|
||||
http://wiki2.dovecot.org/Pigeonhole/Sieve/Examples
|
||||
|
||||
|
||||
|
||||
# orders ignorign default filter is not very effective, because of selecting all orders for billing will select ignored too
|
||||
|
||||
|
||||
# mail system users group? which one is more convinient? if main group does not exists, backend will fail!
|
||||
|
||||
Bash/Python/PHPBackend
|
||||
|
||||
|
||||
# bill action view on a separate process. check memory consumption without debug (236m)
|
||||
|
||||
# services.handler as generator in order to save memory? not swell like a balloon
|
||||
# mailboxes group username instead of mainuser
|
||||
|
||||
import uwsgi
|
||||
from uwsgidecorators import timer
|
||||
|
@ -406,34 +385,23 @@ uwsgi --reload /tmp/project-master.pid
|
|||
# or if uwsgi was started with touch-reload=/tmp/somefile
|
||||
touch /tmp/somefile
|
||||
|
||||
|
||||
# Change zone ttl
|
||||
# batch zone edditing
|
||||
# inherit registers from parent?
|
||||
|
||||
# datetime metric storage granularity: otherwise innacurate detection of billed metric on order.billed_on
|
||||
|
||||
# Serializers.validation migration to DRF3: grep -r 'attrs, source' *|grep -v '~'
|
||||
serailzer self.instance on create.
|
||||
|
||||
# set_password serializer: "just-the-password" not {"password": "password"}
|
||||
|
||||
# use namedtuples?
|
||||
|
||||
# Negative transactionsx
|
||||
|
||||
|
||||
* check certificate: websites directive ssl + domains search on miscellaneous
|
||||
|
||||
|
||||
# Merge websites locations
|
||||
# ValueError: Unable to configure handler 'file': [Errno 13] Permission denied: '/home/orchestra/panel/orchestra.log'
|
||||
|
||||
# billing invoice link on related invoices not overflow nginx GET vars
|
||||
|
||||
* backendLog store method and language... and use it for display_script with correct lexer
|
||||
|
||||
# process monitor data to represent state, or maybe create new resource datas when period expires?
|
||||
# Compute Resource Data history from Monitor Data.
|
||||
|
||||
@register.filter
|
||||
def comma(value):
|
||||
|
@ -444,12 +412,8 @@ def comma(value):
|
|||
return value
|
||||
|
||||
|
||||
|
||||
# payment/bill report allow to change template using a setting variable
|
||||
# Payment transaction stats, graps over time
|
||||
# order stats: service, cost, top profit, etc
|
||||
# TODO remove bill.total
|
||||
|
||||
|
||||
reporter.stories_filed = F('stories_filed') + 1
|
||||
reporter.save()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from urllib import parse
|
||||
|
||||
from django import forms
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin, messages
|
||||
|
@ -34,30 +36,27 @@ class ChangeListDefaultFilter(object):
|
|||
default_changelist_filters = ()
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
defaults = []
|
||||
for key, value in self.default_changelist_filters:
|
||||
set_url_query(request, key, value)
|
||||
defaults.append(key)
|
||||
# hack response cl context in order to hook default filter awaearness
|
||||
# into search_form.html template
|
||||
response = super(ChangeListDefaultFilter, self).changelist_view(request, extra_context)
|
||||
if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
||||
response.context_data['cl'].default_changelist_filters = defaults
|
||||
return response
|
||||
# defaults = []
|
||||
# querystring = request.META['QUERY_STRING']
|
||||
# redirect = False
|
||||
# for field, value in self.default_changelist_filters:
|
||||
# if field not in queryseting:
|
||||
# redirect = True
|
||||
# querystring[field] = value
|
||||
# if redirect:
|
||||
# raise
|
||||
# if not request.META.get('HTTP_REFERER', '').startswith(request.build_absolute_uri()):
|
||||
# querystring = '&'.join('%s=%s' % filed, value in querystring.items())
|
||||
# from django.http import HttpResponseRedirect
|
||||
# return HttpResponseRedirect(request.path + '?%s' % querystring)
|
||||
# return super(ChangeListDefaultFilter, self).changelist_view(request, extra_context=extra_context)
|
||||
# for key, value in self.default_changelist_filters:
|
||||
# set_url_query(request, key, value)
|
||||
# defaults.append(key)
|
||||
# # hack response cl context in order to hook default filter awaearness
|
||||
# # into search_form.html template
|
||||
# response = super(ChangeListDefaultFilter, self).changelist_view(request, extra_context)
|
||||
# if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
||||
# response.context_data['cl'].default_changelist_filters = defaults
|
||||
# return response
|
||||
querystring = request.META['QUERY_STRING']
|
||||
querydict = parse.parse_qs(querystring)
|
||||
redirect = False
|
||||
for field, value in self.default_changelist_filters:
|
||||
if field not in querydict:
|
||||
redirect = True
|
||||
querydict[field] = value
|
||||
if redirect:
|
||||
querystring = parse.urlencode(querydict, doseq=True)
|
||||
return HttpResponseRedirect(request.path + '?%s' % querystring)
|
||||
return super(ChangeListDefaultFilter, self).changelist_view(request, extra_context=extra_context)
|
||||
|
||||
|
||||
class AtLeastOneRequiredInlineFormSet(BaseInlineFormSet):
|
||||
|
|
|
@ -22,8 +22,8 @@ def create_account_creation_form():
|
|||
model = apps.get_model(model)
|
||||
field_name = 'create_%s' % model._meta.model_name
|
||||
label = _("Create %s") % model._meta.verbose_name
|
||||
fields[field_name] = forms.BooleanField(initial=True, required=False, label=label,
|
||||
help_text=help_text)
|
||||
fields[field_name] = forms.BooleanField(
|
||||
initial=True, required=False, label=label, help_text=help_text)
|
||||
|
||||
def clean(self):
|
||||
""" unique usernames between accounts and system users """
|
||||
|
@ -55,7 +55,8 @@ def create_account_creation_form():
|
|||
raise ValidationError(errors)
|
||||
|
||||
def save_model(self, account):
|
||||
account.save(active_systemuser=self.cleaned_data['enable_systemuser'])
|
||||
enable_systemuser=self.cleaned_data['enable_systemuser']
|
||||
account.save(active_systemuser=enable_systemuser)
|
||||
|
||||
def save_related(self, account):
|
||||
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
||||
|
|
|
@ -65,8 +65,9 @@ class Account(auth.AbstractBaseUser):
|
|||
was_active = Account.objects.filter(pk=self.pk).values_list('is_active', flat=True)[0]
|
||||
super(Account, self).save(*args, **kwargs)
|
||||
if created:
|
||||
self.main_systemuser = self.systemusers.create(account=self, username=self.username,
|
||||
password=self.password, is_active=active_systemuser)
|
||||
self.main_systemuser = self.systemusers.create(
|
||||
account=self, username=self.username, password=self.password,
|
||||
is_active=active_systemuser)
|
||||
self.save(update_fields=('main_systemuser',))
|
||||
elif was_active != self.is_active:
|
||||
self.notify_related()
|
||||
|
|
|
@ -55,11 +55,11 @@ class TotalListFilter(SimpleListFilter):
|
|||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() == 'gt':
|
||||
return queryset.filter(computed_total__gt=0)
|
||||
return queryset.filter(approx_total__gt=0)
|
||||
elif self.value() == 'eq':
|
||||
return queryset.filter(computed_total=0)
|
||||
return queryset.filter(approx_total=0)
|
||||
elif self.value() == 'lt':
|
||||
return queryset.filter(computed_total__lt=0)
|
||||
return queryset.filter(approx_total__lt=0)
|
||||
return queryset
|
||||
|
||||
|
||||
|
@ -94,16 +94,17 @@ class PaymentStateListFilter(SimpleListFilter):
|
|||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
# FIXME use queryset.computed_total instead of approx_total, bills.admin.BillAdmin.get_queryset
|
||||
Transaction = queryset.model.transactions.related.related_model
|
||||
if self.value() == 'OPEN':
|
||||
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
||||
elif self.value() == 'PAID':
|
||||
zeros = queryset.filter(computed_total=0, computed_total__isnull=True)
|
||||
zeros = queryset.filter(approx_total=0, approx_total__isnull=True)
|
||||
zeros = zeros.values_list('id', flat=True)
|
||||
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
||||
paid = []
|
||||
relevant = queryset.exclude(computed_total=0, computed_total__isnull=True, is_open=True)
|
||||
for bill_id, total in relevant.values_list('id', 'computed_total'):
|
||||
relevant = queryset.exclude(approx_total=0, approx_total__isnull=True, is_open=True)
|
||||
for bill_id, total in relevant.values_list('id', 'approx_total'):
|
||||
try:
|
||||
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
||||
except KeyError:
|
||||
|
@ -112,8 +113,8 @@ class PaymentStateListFilter(SimpleListFilter):
|
|||
if abs(total) <= abs(ammount):
|
||||
paid.append(bill_id)
|
||||
return queryset.filter(
|
||||
Q(computed_total=0) |
|
||||
Q(computed_total__isnull=True) |
|
||||
Q(approx_total=0) |
|
||||
Q(approx_total__isnull=True) |
|
||||
Q(id__in=paid)
|
||||
).exclude(is_open=True)
|
||||
elif self.value() == 'PENDING':
|
||||
|
@ -122,7 +123,7 @@ class PaymentStateListFilter(SimpleListFilter):
|
|||
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
||||
return queryset.filter(pk__in=non_rejected)
|
||||
elif self.value() == 'BAD_DEBT':
|
||||
closed = queryset.filter(is_open=False).exclude(computed_total=0)
|
||||
closed = queryset.filter(is_open=False).exclude(approx_total=0)
|
||||
return closed.filter(
|
||||
Q(transactions__state=Transaction.REJECTED) |
|
||||
Q(transactions__isnull=True)
|
||||
|
|
|
@ -60,7 +60,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
fields = ('name', 'account_link')
|
||||
inlines = [RecordInline, DomainInline]
|
||||
list_filter = [TopDomainListFilter]
|
||||
change_readonly_fields = ('name',)
|
||||
change_readonly_fields = ('name', 'serial')
|
||||
search_fields = ('name', 'account__username')
|
||||
add_form = BatchDomainCreationAdminForm
|
||||
change_view_actions = [view_zone]
|
||||
|
@ -93,6 +93,18 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
display_websites.short_description = _("Websites")
|
||||
display_websites.allow_tags = True
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
""" Add SOA fields when domain is top """
|
||||
fieldsets = super(DomainAdmin, self).get_fieldsets(request, obj)
|
||||
if obj and obj.is_top:
|
||||
fieldsets += (
|
||||
(_("SOA"), {
|
||||
'classes': ('collapse',),
|
||||
'fields': ('serial', 'refresh', 'retry', 'expire', 'min_ttl'),
|
||||
}),
|
||||
)
|
||||
return fieldsets
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Order by structured name and imporve performance """
|
||||
qs = super(DomainAdmin, self).get_queryset(request)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('domains', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='expire',
|
||||
field=models.IntegerField(null=True, blank=True, help_text='The upper limit in seconds before a zone is considered no longer authoritative (4w by default).', verbose_name='expire'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='min_ttl',
|
||||
field=models.IntegerField(null=True, blank=True, help_text='The negative result TTL (for example, how long a resolver should consider a negative result for a subdomain to be valid before retrying) (1h by default).', verbose_name='refresh'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='refresh',
|
||||
field=models.IntegerField(null=True, blank=True, help_text='The number of seconds before the zone should be refreshed (1d by default).', verbose_name='refresh'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='domain',
|
||||
name='retry',
|
||||
field=models.IntegerField(null=True, blank=True, help_text='The number of seconds before a failed refresh should be retried (2h by default).', verbose_name='retry'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='record',
|
||||
name='value',
|
||||
field=models.CharField(max_length=256, help_text='MX, NS and CNAME records sould end with a dot.', verbose_name='value'),
|
||||
),
|
||||
]
|
|
@ -19,8 +19,25 @@ class Domain(models.Model):
|
|||
related_name='domains', help_text=_("Automatically selected for subdomains."))
|
||||
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomain_set',
|
||||
editable=False)
|
||||
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial,
|
||||
help_text=_("Serial number"))
|
||||
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial, editable=False,
|
||||
help_text=_("A timestamp that changes whenever you update your domain."))
|
||||
refresh = models.IntegerField(_("refresh"), null=True, blank=True,
|
||||
validators=[validators.validate_zone_interval],
|
||||
help_text=_("The number of seconds before the zone should be refreshed "
|
||||
"(<tt>%s</tt> by default).") % settings.DOMAINS_DEFAULT_REFRESH)
|
||||
retry = models.IntegerField(_("retry"), null=True, blank=True,
|
||||
validators=[validators.validate_zone_interval],
|
||||
help_text=_("The number of seconds before a failed refresh should be retried "
|
||||
"(<tt>%s</tt> by default).") % settings.DOMAINS_DEFAULT_RETRY)
|
||||
expire = models.IntegerField(_("expire"), null=True, blank=True,
|
||||
validators=[validators.validate_zone_interval],
|
||||
help_text=_("The upper limit in seconds before a zone is considered no longer "
|
||||
"authoritative (<tt>%s</tt> by default).") % settings.DOMAINS_DEFAULT_EXPIRE)
|
||||
min_ttl = models.IntegerField(_("refresh"), null=True, blank=True,
|
||||
validators=[validators.validate_zone_interval],
|
||||
help_text=_("The negative result TTL (for example, how long a resolver should "
|
||||
"consider a negative result for a subdomain to be valid before retrying) "
|
||||
"(<tt>%s</tt> by default).") % settings.DOMAINS_DEFAULT_MIN_TTL)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -153,10 +170,10 @@ class Domain(models.Model):
|
|||
"%s." % settings.DOMAINS_DEFAULT_NAME_SERVER,
|
||||
utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER),
|
||||
str(self.serial),
|
||||
settings.DOMAINS_DEFAULT_REFRESH,
|
||||
settings.DOMAINS_DEFAULT_RETRY,
|
||||
settings.DOMAINS_DEFAULT_EXPIRATION,
|
||||
settings.DOMAINS_DEFAULT_MIN_CACHING_TIME
|
||||
settings.DOMAINS_DEFAULT_REFRESH if self.refresh is None else self.refresh,
|
||||
settings.DOMAINS_DEFAULT_RETRY if self.retry is None else self.retry,
|
||||
settings.DOMAINS_DEFAULT_EXPIRE if self.expire is None else self.expire,
|
||||
settings.DOMAINS_DEFAULT_MIN_TTL if self.min_ttl is None else self.min_ttl,
|
||||
]
|
||||
records.insert(0, AttrDict(
|
||||
type=Record.SOA,
|
||||
|
|
|
@ -36,13 +36,13 @@ DOMAINS_DEFAULT_RETRY = Setting('DOMAINS_DEFAULT_RETRY',
|
|||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_EXPIRATION = Setting('DOMAINS_DEFAULT_EXPIRATION',
|
||||
DOMAINS_DEFAULT_EXPIRE = Setting('DOMAINS_DEFAULT_EXPIRE',
|
||||
'4w',
|
||||
validators=[validate_zone_interval],
|
||||
)
|
||||
|
||||
|
||||
DOMAINS_DEFAULT_MIN_CACHING_TIME = Setting('DOMAINS_DEFAULT_MIN_CACHING_TIME',
|
||||
DOMAINS_DEFAULT_MIN_TTL = Setting('DOMAINS_DEFAULT_MIN_TTL',
|
||||
'1h',
|
||||
validators=[validate_zone_interval],
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue