diff --git a/TODO.md b/TODO.md
index 7ad9bd01..8590a3fc 100644
--- a/TODO.md
+++ b/TODO.md
@@ -435,7 +435,7 @@ mkhomedir_helper or create ssh homes with bash.rc and such
# DOmain show implicit records
-# if not database_ready(): schedule a retry in 60 seconds, otherwise resources and other dynamic content gets fucked, maybe attach some 'signal' when first query goes trough
+# if not database_ready(): schedule a retry in 60 seconds, otherwise resources and other dynamic content gets fucked, maybe attach some 'signal' when first query goes trough
with database_ready:
shit_happend, otherwise schedule for first query
# Entry.objects.filter()[:1].first() (LIMIT 1)
@@ -443,24 +443,14 @@ mkhomedir_helper or create ssh homes with bash.rc and such
# put "Coordinate Apache restart" inside a bash function for clarity
-# mailscanner phishing, spam, whitelist choices
-
-
# show base and total desglosed
-
# Reverse lOgHistory order by date (lastest first)
-
* setuppostgres use porject_name for db name and user instead of orchestra
-
# POSTFIX web traffic monitor '": uid=" from=<%(user)s>'
# Automatically re-run backends until success? only timedout executions?
# TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects
-
-# INDEXES for most used queries: account FK
-
-
diff --git a/orchestra/contrib/bills/admin.py b/orchestra/contrib/bills/admin.py
index 65d0c9c8..4631b15d 100644
--- a/orchestra/contrib/bills/admin.py
+++ b/orchestra/contrib/bills/admin.py
@@ -64,10 +64,10 @@ class BillLineInline(admin.TabularInline):
kwargs['widget'] = forms.TextInput(attrs={'size':'50'})
elif db_field.name not in ('start_on', 'end_on'):
kwargs['widget'] = forms.TextInput(attrs={'size':'6'})
- return super(BillLineInline, self).formfield_for_dbfield(db_field, **kwargs)
+ return super().formfield_for_dbfield(db_field, **kwargs)
def get_queryset(self, request):
- qs = super(BillLineInline, self).get_queryset(request)
+ qs = super().get_queryset(request)
return qs.prefetch_related('sublines').select_related('order')
@@ -141,7 +141,7 @@ class BillLineAdmin(admin.ModelAdmin):
display_total.admin_order_field = 'computed_total'
def get_queryset(self, request):
- qs = super(BillLineAdmin, self).get_queryset(request)
+ qs = super().get_queryset(request)
qs = qs.annotate(
subline_total=Sum('sublines__total'),
computed_total=(F('subtotal') + Sum(Coalesce('sublines__total', 0))) * (1+F('tax')/100),
@@ -151,7 +151,7 @@ class BillLineAdmin(admin.ModelAdmin):
class BillLineManagerAdmin(BillLineAdmin):
def get_queryset(self, request):
- qset = super(BillLineManagerAdmin, self).get_queryset(request)
+ qset = super().get_queryset(request)
if self.bill_ids:
return qset.filter(bill_id__in=self.bill_ids)
return qset
@@ -182,7 +182,7 @@ class BillLineManagerAdmin(BillLineAdmin):
'title': title,
}
context.update(extra_context or {})
- return super(BillLineManagerAdmin, self).changelist_view(request, context)
+ return super().changelist_view(request, context)
class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
@@ -288,7 +288,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
def get_urls(self):
""" Hook bill lines management URLs on bill admin """
- urls = super(BillAdmin, self).get_urls()
+ urls = super().get_urls()
admin_site = self.admin_site
extra_urls = [
url("^manage-lines/$",
@@ -298,13 +298,13 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
return extra_urls + urls
def get_readonly_fields(self, request, obj=None):
- fields = super(BillAdmin, self).get_readonly_fields(request, obj)
+ fields = super().get_readonly_fields(request, obj)
if obj and not obj.is_open:
fields += self.add_fields
return fields
def get_fieldsets(self, request, obj=None):
- fieldsets = super(BillAdmin, self).get_fieldsets(request, obj)
+ fieldsets = super().get_fieldsets(request, obj)
if obj:
# Switches between amend_of_link and amend_links fields
if obj.amend_of_id:
@@ -316,7 +316,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
return fieldsets
def get_change_view_actions(self, obj=None):
- actions = super(BillAdmin, self).get_change_view_actions(obj)
+ actions = super().get_change_view_actions(obj)
exclude = []
if obj:
if not obj.is_open:
@@ -326,7 +326,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
return [action for action in actions if action.__name__ not in exclude]
def get_inline_instances(self, request, obj=None):
- inlines = super(BillAdmin, self).get_inline_instances(request, obj)
+ inlines = super().get_inline_instances(request, obj)
if obj and not obj.is_open:
return [inline for inline in inlines if type(inline) != BillLineInline]
return [inline for inline in inlines if type(inline) != ClosedBillLineInline]
@@ -337,13 +337,13 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4})
elif db_field.name == 'html':
kwargs['widget'] = forms.Textarea(attrs={'cols': 150, 'rows': 20})
- formfield = super(BillAdmin, self).formfield_for_dbfield(db_field, **kwargs)
+ formfield = super().formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'amend_of':
formfield.queryset = formfield.queryset.filter(is_open=False)
return formfield
def get_queryset(self, request):
- qs = super(BillAdmin, self).get_queryset(request)
+ qs = super().get_queryset(request)
qs = qs.annotate(
models.Count('lines'),
# FIXME https://code.djangoproject.com/ticket/10060
@@ -360,7 +360,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin):
# TODO raise404, here and everywhere
bill = self.get_object(request, unquote(object_id))
actions.validate_contact(request, bill, error=False)
- return super(BillAdmin, self).change_view(request, object_id, **kwargs)
+ return super().change_view(request, object_id, **kwargs)
admin.site.register(Bill, BillAdmin)
@@ -384,7 +384,7 @@ class BillContactInline(admin.StackedInline):
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2})
if db_field.name == 'email_usage':
kwargs['widget'] = paddingCheckboxSelectMultiple(45)
- return super(BillContactInline, self).formfield_for_dbfield(db_field, **kwargs)
+ return super().formfield_for_dbfield(db_field, **kwargs)
def has_bill_contact(account):
diff --git a/orchestra/contrib/bills/models.py b/orchestra/contrib/bills/models.py
index 69f56342..d0bc3d6d 100644
--- a/orchestra/contrib/bills/models.py
+++ b/orchestra/contrib/bills/models.py
@@ -404,7 +404,8 @@ class BillLine(models.Model):
start_on = models.DateField(_("start"))
end_on = models.DateField(_("end"), null=True, blank=True)
order = models.ForeignKey(settings.BILLS_ORDER_MODEL, null=True, blank=True,
- help_text=_("Informative link back to the order"), on_delete=models.SET_NULL)
+ related_name='lines', on_delete=models.SET_NULL,
+ help_text=_("Informative link back to the order"))
order_billed_on = models.DateField(_("order billed"), null=True, blank=True)
order_billed_until = models.DateField(_("order billed until"), null=True, blank=True)
created_on = models.DateField(_("created"), auto_now_add=True)
diff --git a/orchestra/contrib/domains/admin.py b/orchestra/contrib/domains/admin.py
index 09d61c57..e735c1da 100644
--- a/orchestra/contrib/domains/admin.py
+++ b/orchestra/contrib/domains/admin.py
@@ -104,6 +104,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
fieldsets += (
(_("SOA"), {
'classes': ('collapse',),
+ 'description': _(
+ "SOA (Start of Authority) records are used to determine how your "
+ "zone propagates to the secondary nameservers."),
'fields': ('serial', 'refresh', 'retry', 'expire', 'min_ttl'),
}),
)
diff --git a/orchestra/contrib/lists/admin.py b/orchestra/contrib/lists/admin.py
index 0ddc1cc8..15c6ff9a 100644
--- a/orchestra/contrib/lists/admin.py
+++ b/orchestra/contrib/lists/admin.py
@@ -10,6 +10,7 @@ from orchestra.contrib.accounts.actions import list_accounts
from orchestra.contrib.accounts.admin import SelectAccountAdminMixin
from orchestra.contrib.accounts.filters import IsActiveListFilter
+from . import settings
from .forms import ListCreationForm, ListChangeForm
from .models import List
@@ -39,6 +40,8 @@ class ListAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModel
}),
(_("Address"), {
'classes': ('wide',),
+ 'description': _("Additional address besides the default <name>@%s"
+ ) % settings.LISTS_DEFAULT_DOMAIN,
'fields': (('address_name', 'address_domain'),)
}),
(_("Admin"), {
diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py
index f22308c7..8ec1ed36 100644
--- a/orchestra/contrib/mailboxes/admin.py
+++ b/orchestra/contrib/mailboxes/admin.py
@@ -49,6 +49,8 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
}),
(_("Custom filtering"), {
'classes': ('collapse',),
+ 'description': _("Please remember to select custom filtering "
+ "if you want this filter to be applied."),
'fields': ('custom_filtering',),
}),
(_("Addresses"), {
diff --git a/orchestra/contrib/orchestration/management/commands/orchestrate.py b/orchestra/contrib/orchestration/management/commands/orchestrate.py
index cb545dea..8fb7def3 100644
--- a/orchestra/contrib/orchestration/management/commands/orchestrate.py
+++ b/orchestra/contrib/orchestration/management/commands/orchestrate.py
@@ -78,16 +78,16 @@ class Command(BaseCommand):
for instance in queryset:
manager.collect(instance, action, operations=operations, route_cache=route_cache)
scripts, serialize = manager.generate(operations)
- servers = []
+ servers = set()
# Print scripts
for key, value in scripts.items():
route, __, __ = key
backend, operations = value
- servers.append(str(route.host))
+ servers.add(str(route.host))
self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host))
for method, commands in backend.scripts:
script = '\n'.join(commands)
- self.stdout.write(script)
+ self.stdout.write(script.encode('ascii', errors='replace').decode())
if interactive:
context = {
'servers': ', '.join(servers),
diff --git a/orchestra/contrib/orders/admin.py b/orchestra/contrib/orders/admin.py
index 77e6d27e..f2f3ac70 100644
--- a/orchestra/contrib/orders/admin.py
+++ b/orchestra/contrib/orders/admin.py
@@ -1,3 +1,4 @@
+from django import forms
from django.contrib import admin
from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import Prefetch
@@ -38,8 +39,9 @@ class MetricStorageInline(admin.TabularInline):
change_view = bool(self.parent_object and self.parent_object.pk)
if change_view:
qs = qs.order_by('-id')
+ parent_id = self.parent_object.pk
try:
- tenth_id = qs.filter(order_id=self.parent_object.pk).values_list('id', flat=True)[9]
+ tenth_id = qs.filter(order_id=parent_id).values_list('id', flat=True)[9]
except IndexError:
pass
else:
@@ -72,7 +74,37 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
Prefetch('metrics', queryset=MetricStorage.objects.order_by('-id')),
)
list_select_related = ('account', 'service')
- readonly_fields = ('content_object_repr', 'content_object_link')
+ add_fieldsets = (
+ (None, {
+ 'fields': ('account', 'service')
+ }),
+ (_("Object"), {
+ 'fields': ('content_type', 'object_id',),
+ }),
+ (_("State"), {
+ 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric',
+ 'billed_until' )
+ }),
+ (None, {
+ 'fields': ('description', 'ignore',),
+ }),
+ )
+ fieldsets = (
+ (None, {
+ 'fields': ('account_link', 'service_link', 'content_object_link'),
+ }),
+ (_("State"), {
+ 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric',
+ 'billed_until' )
+ }),
+ (None, {
+ 'fields': ('description', 'ignore', 'bills_links'),
+ }),
+ )
+ readonly_fields = (
+ 'content_object_repr', 'content_object_link', 'bills_links', 'account_link',
+ 'service_link'
+ )
service_link = admin_link('service')
display_registered_on = admin_date('registered_on')
@@ -99,6 +131,15 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
content_object_link.allow_tags = True
content_object_link.admin_order_field = 'content_object_repr'
+ def bills_links(self, order):
+ bills = []
+ make_link = admin_link()
+ for line in order.lines.select_related('bill').distinct('bill'):
+ bills.append(make_link(line.bill))
+ return '