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
|
* 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 )
|
* 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
|
* 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
|
* Autocomplete admin fields like <site_name>.phplist... with js
|
||||||
|
|
||||||
* allow empty metric pack for default rates? changes on rating algo
|
* 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
|
* payment methods icons
|
||||||
* use server.name | server.address on python backends, like gitlab instead of settings?
|
* use server.name | server.address on python backends, like gitlab instead of settings?
|
||||||
|
@ -373,23 +365,10 @@ method(
|
||||||
arg, arg, arg)
|
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
|
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
|
# services.handler as generator in order to save memory? not swell like a balloon
|
||||||
# mailboxes group username instead of mainuser
|
|
||||||
|
|
||||||
import uwsgi
|
import uwsgi
|
||||||
from uwsgidecorators import timer
|
from uwsgidecorators import timer
|
||||||
|
@ -406,34 +385,23 @@ uwsgi --reload /tmp/project-master.pid
|
||||||
# or if uwsgi was started with touch-reload=/tmp/somefile
|
# or if uwsgi was started with touch-reload=/tmp/somefile
|
||||||
touch /tmp/somefile
|
touch /tmp/somefile
|
||||||
|
|
||||||
|
|
||||||
# Change zone ttl
|
# Change zone ttl
|
||||||
# batch zone edditing
|
# batch zone edditing
|
||||||
# inherit registers from parent?
|
|
||||||
|
|
||||||
# datetime metric storage granularity: otherwise innacurate detection of billed metric on order.billed_on
|
# 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 '~'
|
# Serializers.validation migration to DRF3: grep -r 'attrs, source' *|grep -v '~'
|
||||||
serailzer self.instance on create.
|
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
|
* 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'
|
# 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
|
# 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
|
* 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
|
@register.filter
|
||||||
def comma(value):
|
def comma(value):
|
||||||
|
@ -444,12 +412,8 @@ def comma(value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# payment/bill report allow to change template using a setting variable
|
# payment/bill report allow to change template using a setting variable
|
||||||
# Payment transaction stats, graps over time
|
# 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.stories_filed = F('stories_filed') + 1
|
||||||
reporter.save()
|
reporter.save()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from urllib import parse
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import admin, messages
|
from django.contrib import admin, messages
|
||||||
|
@ -34,30 +36,27 @@ class ChangeListDefaultFilter(object):
|
||||||
default_changelist_filters = ()
|
default_changelist_filters = ()
|
||||||
|
|
||||||
def changelist_view(self, request, extra_context=None):
|
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 = []
|
# defaults = []
|
||||||
# querystring = request.META['QUERY_STRING']
|
# for key, value in self.default_changelist_filters:
|
||||||
# redirect = False
|
# set_url_query(request, key, value)
|
||||||
# for field, value in self.default_changelist_filters:
|
# defaults.append(key)
|
||||||
# if field not in queryseting:
|
# # hack response cl context in order to hook default filter awaearness
|
||||||
# redirect = True
|
# # into search_form.html template
|
||||||
# querystring[field] = value
|
# response = super(ChangeListDefaultFilter, self).changelist_view(request, extra_context)
|
||||||
# if redirect:
|
# if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
||||||
# raise
|
# response.context_data['cl'].default_changelist_filters = defaults
|
||||||
# if not request.META.get('HTTP_REFERER', '').startswith(request.build_absolute_uri()):
|
# return response
|
||||||
# querystring = '&'.join('%s=%s' % filed, value in querystring.items())
|
querystring = request.META['QUERY_STRING']
|
||||||
# from django.http import HttpResponseRedirect
|
querydict = parse.parse_qs(querystring)
|
||||||
# return HttpResponseRedirect(request.path + '?%s' % querystring)
|
redirect = False
|
||||||
# return super(ChangeListDefaultFilter, self).changelist_view(request, extra_context=extra_context)
|
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):
|
class AtLeastOneRequiredInlineFormSet(BaseInlineFormSet):
|
||||||
|
|
|
@ -22,8 +22,8 @@ def create_account_creation_form():
|
||||||
model = apps.get_model(model)
|
model = apps.get_model(model)
|
||||||
field_name = 'create_%s' % model._meta.model_name
|
field_name = 'create_%s' % model._meta.model_name
|
||||||
label = _("Create %s") % model._meta.verbose_name
|
label = _("Create %s") % model._meta.verbose_name
|
||||||
fields[field_name] = forms.BooleanField(initial=True, required=False, label=label,
|
fields[field_name] = forms.BooleanField(
|
||||||
help_text=help_text)
|
initial=True, required=False, label=label, help_text=help_text)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" unique usernames between accounts and system users """
|
""" unique usernames between accounts and system users """
|
||||||
|
@ -55,7 +55,8 @@ def create_account_creation_form():
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
||||||
def save_model(self, account):
|
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):
|
def save_related(self, account):
|
||||||
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
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]
|
was_active = Account.objects.filter(pk=self.pk).values_list('is_active', flat=True)[0]
|
||||||
super(Account, self).save(*args, **kwargs)
|
super(Account, self).save(*args, **kwargs)
|
||||||
if created:
|
if created:
|
||||||
self.main_systemuser = self.systemusers.create(account=self, username=self.username,
|
self.main_systemuser = self.systemusers.create(
|
||||||
password=self.password, is_active=active_systemuser)
|
account=self, username=self.username, password=self.password,
|
||||||
|
is_active=active_systemuser)
|
||||||
self.save(update_fields=('main_systemuser',))
|
self.save(update_fields=('main_systemuser',))
|
||||||
elif was_active != self.is_active:
|
elif was_active != self.is_active:
|
||||||
self.notify_related()
|
self.notify_related()
|
||||||
|
|
|
@ -55,11 +55,11 @@ class TotalListFilter(SimpleListFilter):
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
def queryset(self, request, queryset):
|
||||||
if self.value() == 'gt':
|
if self.value() == 'gt':
|
||||||
return queryset.filter(computed_total__gt=0)
|
return queryset.filter(approx_total__gt=0)
|
||||||
elif self.value() == 'eq':
|
elif self.value() == 'eq':
|
||||||
return queryset.filter(computed_total=0)
|
return queryset.filter(approx_total=0)
|
||||||
elif self.value() == 'lt':
|
elif self.value() == 'lt':
|
||||||
return queryset.filter(computed_total__lt=0)
|
return queryset.filter(approx_total__lt=0)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,16 +94,17 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
)
|
)
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
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
|
Transaction = queryset.model.transactions.related.related_model
|
||||||
if self.value() == 'OPEN':
|
if self.value() == 'OPEN':
|
||||||
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
||||||
elif self.value() == 'PAID':
|
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)
|
zeros = zeros.values_list('id', flat=True)
|
||||||
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
||||||
paid = []
|
paid = []
|
||||||
relevant = queryset.exclude(computed_total=0, computed_total__isnull=True, is_open=True)
|
relevant = queryset.exclude(approx_total=0, approx_total__isnull=True, is_open=True)
|
||||||
for bill_id, total in relevant.values_list('id', 'computed_total'):
|
for bill_id, total in relevant.values_list('id', 'approx_total'):
|
||||||
try:
|
try:
|
||||||
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -112,8 +113,8 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
if abs(total) <= abs(ammount):
|
if abs(total) <= abs(ammount):
|
||||||
paid.append(bill_id)
|
paid.append(bill_id)
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
Q(computed_total=0) |
|
Q(approx_total=0) |
|
||||||
Q(computed_total__isnull=True) |
|
Q(approx_total__isnull=True) |
|
||||||
Q(id__in=paid)
|
Q(id__in=paid)
|
||||||
).exclude(is_open=True)
|
).exclude(is_open=True)
|
||||||
elif self.value() == 'PENDING':
|
elif self.value() == 'PENDING':
|
||||||
|
@ -122,7 +123,7 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
||||||
return queryset.filter(pk__in=non_rejected)
|
return queryset.filter(pk__in=non_rejected)
|
||||||
elif self.value() == 'BAD_DEBT':
|
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(
|
return closed.filter(
|
||||||
Q(transactions__state=Transaction.REJECTED) |
|
Q(transactions__state=Transaction.REJECTED) |
|
||||||
Q(transactions__isnull=True)
|
Q(transactions__isnull=True)
|
||||||
|
|
|
@ -60,7 +60,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
fields = ('name', 'account_link')
|
fields = ('name', 'account_link')
|
||||||
inlines = [RecordInline, DomainInline]
|
inlines = [RecordInline, DomainInline]
|
||||||
list_filter = [TopDomainListFilter]
|
list_filter = [TopDomainListFilter]
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name', 'serial')
|
||||||
search_fields = ('name', 'account__username')
|
search_fields = ('name', 'account__username')
|
||||||
add_form = BatchDomainCreationAdminForm
|
add_form = BatchDomainCreationAdminForm
|
||||||
change_view_actions = [view_zone]
|
change_view_actions = [view_zone]
|
||||||
|
@ -93,6 +93,18 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
display_websites.short_description = _("Websites")
|
display_websites.short_description = _("Websites")
|
||||||
display_websites.allow_tags = True
|
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):
|
def get_queryset(self, request):
|
||||||
""" Order by structured name and imporve performance """
|
""" Order by structured name and imporve performance """
|
||||||
qs = super(DomainAdmin, self).get_queryset(request)
|
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."))
|
related_name='domains', help_text=_("Automatically selected for subdomains."))
|
||||||
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomain_set',
|
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomain_set',
|
||||||
editable=False)
|
editable=False)
|
||||||
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial,
|
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial, editable=False,
|
||||||
help_text=_("Serial number"))
|
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):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -153,10 +170,10 @@ class Domain(models.Model):
|
||||||
"%s." % settings.DOMAINS_DEFAULT_NAME_SERVER,
|
"%s." % settings.DOMAINS_DEFAULT_NAME_SERVER,
|
||||||
utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER),
|
utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER),
|
||||||
str(self.serial),
|
str(self.serial),
|
||||||
settings.DOMAINS_DEFAULT_REFRESH,
|
settings.DOMAINS_DEFAULT_REFRESH if self.refresh is None else self.refresh,
|
||||||
settings.DOMAINS_DEFAULT_RETRY,
|
settings.DOMAINS_DEFAULT_RETRY if self.retry is None else self.retry,
|
||||||
settings.DOMAINS_DEFAULT_EXPIRATION,
|
settings.DOMAINS_DEFAULT_EXPIRE if self.expire is None else self.expire,
|
||||||
settings.DOMAINS_DEFAULT_MIN_CACHING_TIME
|
settings.DOMAINS_DEFAULT_MIN_TTL if self.min_ttl is None else self.min_ttl,
|
||||||
]
|
]
|
||||||
records.insert(0, AttrDict(
|
records.insert(0, AttrDict(
|
||||||
type=Record.SOA,
|
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',
|
'4w',
|
||||||
validators=[validate_zone_interval],
|
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',
|
'1h',
|
||||||
validators=[validate_zone_interval],
|
validators=[validate_zone_interval],
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue