Merge pull request #8 from ribaguifi/dev/django2.1-admin
Refactor admin code to support Django 2.1
This commit is contained in:
commit
7b59931bcf
|
@ -5,7 +5,7 @@ from django import forms
|
|||
from django.contrib.admin import helpers
|
||||
from django.core import validators
|
||||
from django.forms.models import modelformset_factory, BaseModelFormSet
|
||||
from django.template import Template, Context
|
||||
from django.template import Template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.forms.widgets import SpanWidget
|
||||
|
@ -28,9 +28,9 @@ class AdminFormMixin(object):
|
|||
' {% include "admin/includes/fieldset.html" %}'
|
||||
'{% endfor %}'
|
||||
)
|
||||
context = Context({
|
||||
context = {
|
||||
'adminform': adminform
|
||||
})
|
||||
}
|
||||
return template.render(context)
|
||||
|
||||
|
||||
|
@ -71,9 +71,9 @@ class AdminFormSet(BaseModelFormSet):
|
|||
</div>
|
||||
</div>""")
|
||||
)
|
||||
context = Context({
|
||||
context = {
|
||||
'formset': self
|
||||
})
|
||||
}
|
||||
return template.render(context)
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.urls import reverse, NoReverseMatch
|
|||
from django.db import models
|
||||
from django.shortcuts import redirect
|
||||
from django.utils import timezone
|
||||
from django.utils.html import escape
|
||||
from django.utils.html import escape, format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from orchestra.models.utils import get_field_value
|
||||
|
@ -113,21 +113,21 @@ def admin_link(*args, **kwargs):
|
|||
return '---'
|
||||
if not getattr(obj, 'pk', None):
|
||||
return '---'
|
||||
display = kwargs.get('display')
|
||||
if display:
|
||||
display = getattr(obj, display, display)
|
||||
display_ = kwargs.get('display')
|
||||
if display_:
|
||||
display_ = getattr(obj, display_, display_)
|
||||
else:
|
||||
display = obj
|
||||
display_ = obj
|
||||
try:
|
||||
url = change_url(obj)
|
||||
except NoReverseMatch:
|
||||
# Does not has admin
|
||||
return str(display)
|
||||
return str(display_)
|
||||
extra = ''
|
||||
if kwargs['popup']:
|
||||
extra = 'onclick="return showAddAnotherPopup(this);"'
|
||||
extra = mark_safe('onclick="return showAddAnotherPopup(this);"')
|
||||
title = "Change %s" % obj._meta.verbose_name
|
||||
return mark_safe('<a href="%s" title="%s" %s>%s</a>' % (url, title, extra, display))
|
||||
return format_html('<a href="{}" title="{}" {}>{}</a>', url, title, extra, display_)
|
||||
|
||||
|
||||
@admin_field
|
||||
|
@ -158,7 +158,7 @@ def admin_date(*args, **kwargs):
|
|||
date = date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
||||
else:
|
||||
date = date.strftime("%Y-%m-%d")
|
||||
return '<span title="{0}">{1}</span>'.format(date, escape(natural))
|
||||
return format_html('<span title="{0}">{1}</span>', date, natural)
|
||||
|
||||
|
||||
def get_object_from_url(modeladmin, request):
|
||||
|
|
|
@ -175,7 +175,7 @@ def delete_related_services(modeladmin, request, queryset):
|
|||
for model, objs in collector.model_objs.items():
|
||||
count = 0
|
||||
# discount main systemuser
|
||||
if model is modeladmin.model.main_systemuser.field.model:
|
||||
if model is modeladmin.model.main_systemuser.field.related_model:
|
||||
count = len(objs) - 1
|
||||
# Discount account
|
||||
elif model is not modeladmin.model and model in registered_services:
|
||||
|
|
|
@ -158,6 +158,7 @@ class AccountListAdmin(AccountAdmin):
|
|||
actions = None
|
||||
change_list_template = 'admin/accounts/account/select_account_list.html'
|
||||
|
||||
@mark_safe
|
||||
def select_account(self, instance):
|
||||
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
||||
context = {
|
||||
|
@ -167,7 +168,6 @@ class AccountListAdmin(AccountAdmin):
|
|||
}
|
||||
return _('<a href="%(url)s">%(plus)s Add to %(name)s</a>') % context
|
||||
select_account.short_description = _("account")
|
||||
select_account.allow_tags = True
|
||||
select_account.admin_order_field = 'username'
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
|
@ -207,6 +207,7 @@ class AccountAdminMixin(object):
|
|||
account = None
|
||||
list_select_related = ('account',)
|
||||
|
||||
@mark_safe
|
||||
def display_active(self, instance):
|
||||
if not instance.is_active:
|
||||
return '<img src="%s" alt="False">' % static('admin/img/icon-no.svg')
|
||||
|
@ -215,14 +216,12 @@ class AccountAdminMixin(object):
|
|||
return '<img style="width:13px" src="%s" alt="False" title="%s">' % (static('admin/img/inline-delete.svg'), msg)
|
||||
return '<img src="%s" alt="False">' % static('admin/img/icon-yes.svg')
|
||||
display_active.short_description = _("active")
|
||||
display_active.allow_tags = True
|
||||
display_active.admin_order_field = 'is_active'
|
||||
|
||||
def account_link(self, instance):
|
||||
account = instance.account if instance.pk else self.account
|
||||
return admin_link()(account)
|
||||
account_link.short_description = _("account")
|
||||
account_link.allow_tags = True
|
||||
account_link.admin_order_field = 'account__username'
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
|
|
|
@ -47,7 +47,7 @@ def create_account_creation_form():
|
|||
# Previous validation error
|
||||
return
|
||||
errors = {}
|
||||
systemuser_model = Account.main_systemuser.field.model
|
||||
systemuser_model = Account.main_systemuser.field.related_model
|
||||
if systemuser_model.objects.filter(username=account.username).exists():
|
||||
errors['username'] = _("A system user with this name already exists.")
|
||||
for model, key, related_kwargs, __ in create_related:
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.db import models
|
|||
from django.db.models import F, Sum, Prefetch
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.templatetags.static import static
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import redirect
|
||||
|
@ -15,7 +16,7 @@ from orchestra.admin import ExtendedModelAdmin
|
|||
from orchestra.admin.utils import admin_date, insertattr, admin_link, change_url
|
||||
from orchestra.contrib.accounts.actions import list_accounts
|
||||
from orchestra.contrib.accounts.admin import AccountAdminMixin, AccountAdmin
|
||||
from orchestra.forms.widgets import paddingCheckboxSelectMultiple
|
||||
from orchestra.forms.widgets import PaddingCheckboxSelectMultiple
|
||||
|
||||
from . import settings, actions
|
||||
from .filters import (BillTypeListFilter, HasBillContactListFilter, TotalListFilter,
|
||||
|
@ -67,6 +68,7 @@ class BillLineInline(admin.TabularInline):
|
|||
|
||||
order_link = admin_link('order', display='pk')
|
||||
|
||||
@mark_safe
|
||||
def display_total(self, line):
|
||||
if line.pk:
|
||||
total = line.compute_total()
|
||||
|
@ -78,7 +80,6 @@ class BillLineInline(admin.TabularInline):
|
|||
return '<a href="%s" title="%s">%s <img src="%s"></img></a>' % (url, content, total, img)
|
||||
return '<a href="%s">%s</a>' % (url, total)
|
||||
display_total.short_description = _("Total")
|
||||
display_total.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
|
@ -104,27 +105,26 @@ class ClosedBillLineInline(BillLineInline):
|
|||
readonly_fields = fields
|
||||
can_delete = False
|
||||
|
||||
@mark_safe
|
||||
def display_description(self, line):
|
||||
descriptions = [line.description]
|
||||
for subline in line.sublines.all():
|
||||
descriptions.append(' '*4+subline.description)
|
||||
descriptions.append(' ' * 4 + subline.description)
|
||||
return '<br>'.join(descriptions)
|
||||
display_description.short_description = _("Description")
|
||||
display_description.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def display_subtotal(self, line):
|
||||
subtotals = [' ' + str(line.subtotal)]
|
||||
for subline in line.sublines.all():
|
||||
subtotals.append(str(subline.total))
|
||||
return '<br>'.join(subtotals)
|
||||
display_subtotal.short_description = _("Subtotal")
|
||||
display_subtotal.allow_tags = True
|
||||
|
||||
def display_total(self, line):
|
||||
if line.pk:
|
||||
return line.compute_total()
|
||||
display_total.short_description = _("Total")
|
||||
display_total.allow_tags = True
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
@ -242,6 +242,7 @@ class BillLineManagerAdmin(BillLineAdmin):
|
|||
|
||||
|
||||
class BillAdminMixin(AccountAdminMixin):
|
||||
@mark_safe
|
||||
def display_total_with_subtotals(self, bill):
|
||||
if bill.pk:
|
||||
currency = settings.BILLS_CURRENCY.lower()
|
||||
|
@ -251,10 +252,10 @@ class BillAdminMixin(AccountAdminMixin):
|
|||
subtotals.append(_("Taxes %s%% VAT %s &%s;") % (tax, subtotal[1], currency))
|
||||
subtotals = '\n'.join(subtotals)
|
||||
return '<span title="%s">%s &%s;</span>' % (subtotals, bill.compute_total(), currency)
|
||||
display_total_with_subtotals.allow_tags = True
|
||||
display_total_with_subtotals.short_description = _("total")
|
||||
display_total_with_subtotals.admin_order_field = 'approx_total'
|
||||
|
||||
@mark_safe
|
||||
def display_payment_state(self, bill):
|
||||
if bill.pk:
|
||||
t_opts = bill.transactions.model._meta
|
||||
|
@ -276,7 +277,6 @@ class BillAdminMixin(AccountAdminMixin):
|
|||
color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey')
|
||||
return '<a href="{url}" style="color:{color}" title="{title}">{name}</a>'.format(
|
||||
url=url, color=color, name=state, title=title)
|
||||
display_payment_state.allow_tags = True
|
||||
display_payment_state.short_description = _("Payment")
|
||||
|
||||
def get_queryset(self, request):
|
||||
|
@ -376,16 +376,14 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
|||
|
||||
def display_total(self, bill):
|
||||
currency = settings.BILLS_CURRENCY.lower()
|
||||
return '%s &%s;' % (bill.compute_total(), currency)
|
||||
display_total.allow_tags = True
|
||||
return format_html('{} &{};', bill.compute_total(), currency)
|
||||
display_total.short_description = _("total")
|
||||
display_total.admin_order_field = 'approx_total'
|
||||
|
||||
def type_link(self, bill):
|
||||
bill_type = bill.type.lower()
|
||||
url = reverse('admin:bills_%s_changelist' % bill_type)
|
||||
return '<a href="%s">%s</a>' % (url, bill.get_type_display())
|
||||
type_link.allow_tags = True
|
||||
return format_html('<a href="{}">{}</a>', url, bill.get_type_display())
|
||||
type_link.short_description = _("type")
|
||||
type_link.admin_order_field = 'type'
|
||||
|
||||
|
@ -479,7 +477,7 @@ class BillContactInline(admin.StackedInline):
|
|||
if db_field.name == 'address':
|
||||
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2})
|
||||
if db_field.name == 'email_usage':
|
||||
kwargs['widget'] = paddingCheckboxSelectMultiple(45)
|
||||
kwargs['widget'] = PaddingCheckboxSelectMultiple(45)
|
||||
return super().formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ def validate_contact(request, bill, error=True):
|
|||
message = msg.format(relation=_("Related"), account=account, url=url)
|
||||
send(request, mark_safe(message))
|
||||
valid = False
|
||||
main = type(bill).account.field.model.objects.get_main()
|
||||
main = type(bill).account.field.related_model.objects.get_main()
|
||||
if not hasattr(main, 'billcontact'):
|
||||
account = force_text(main)
|
||||
url = reverse('admin:accounts_account_change', args=(main.id,))
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.core.validators import ValidationError, RegexValidator
|
|||
from django.db import models
|
||||
from django.db.models import F, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.template import loader, Context
|
||||
from django.template import loader
|
||||
from django.utils import timezone, translation
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.functional import cached_property
|
||||
|
@ -303,7 +303,7 @@ class Bill(models.Model):
|
|||
with translation.override(language or self.account.language):
|
||||
if payment is False:
|
||||
payment = self.account.paymentsources.get_default()
|
||||
context = Context({
|
||||
context = {
|
||||
'bill': self,
|
||||
'lines': self.lines.all().prefetch_related('sublines'),
|
||||
'seller': self.seller,
|
||||
|
@ -318,7 +318,7 @@ class Bill(models.Model):
|
|||
'payment': payment and payment.get_bill_context(),
|
||||
'default_due_date': self.get_due_date(payment=payment),
|
||||
'now': timezone.now(),
|
||||
})
|
||||
}
|
||||
template_name = 'BILLS_%s_TEMPLATE' % self.get_type()
|
||||
template = getattr(settings, template_name, settings.BILLS_DEFAULT_TEMPLATE)
|
||||
bill_template = loader.get_template(template)
|
||||
|
|
|
@ -7,7 +7,7 @@ from orchestra.admin.actions import SendEmail
|
|||
from orchestra.admin.utils import insertattr, change_url
|
||||
from orchestra.contrib.accounts.actions import list_accounts
|
||||
from orchestra.contrib.accounts.admin import AccountAdmin, AccountAdminMixin
|
||||
from orchestra.forms.widgets import paddingCheckboxSelectMultiple
|
||||
from orchestra.forms.widgets import PaddingCheckboxSelectMultiple
|
||||
|
||||
from .filters import EmailUsageListFilter
|
||||
from .models import Contact
|
||||
|
@ -72,7 +72,7 @@ class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
if db_field.name == 'address':
|
||||
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2})
|
||||
if db_field.name == 'email_usage':
|
||||
kwargs['widget'] = paddingCheckboxSelectMultiple(130)
|
||||
kwargs['widget'] = PaddingCheckboxSelectMultiple(130)
|
||||
return super(ContactAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
|
@ -101,7 +101,7 @@ class ContactInline(admin.StackedInline):
|
|||
if db_field.name == 'address':
|
||||
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2})
|
||||
if db_field.name == 'email_usage':
|
||||
kwargs['widget'] = paddingCheckboxSelectMultiple(45)
|
||||
kwargs['widget'] = PaddingCheckboxSelectMultiple(45)
|
||||
return super(ContactInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from django.conf.urls import url
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||
|
@ -50,14 +52,14 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
list_prefetch_related = ('users',)
|
||||
actions = (list_accounts, save_selected)
|
||||
|
||||
@mark_safe
|
||||
def display_users(self, db):
|
||||
links = []
|
||||
for user in db.users.all():
|
||||
link = '<a href="%s">%s</a>' % (change_url(user), user.username)
|
||||
link = format_html('<a href="{}">{}</a>', change_url(user), user.username)
|
||||
links.append(link)
|
||||
return '<br>'.join(links)
|
||||
display_users.short_description = _("Users")
|
||||
display_users.allow_tags = True
|
||||
display_users.admin_order_field = 'users__username'
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
|
@ -99,14 +101,14 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
|||
list_prefetch_related = ('databases',)
|
||||
actions = (list_accounts, save_selected)
|
||||
|
||||
@mark_safe
|
||||
def display_databases(self, user):
|
||||
links = []
|
||||
for db in user.databases.all():
|
||||
link = '<a href="%s">%s</a>' % (change_url(db), db.name)
|
||||
link = format_html('<a href="{}">{}</a>', change_url(db), db.name)
|
||||
links.append(link)
|
||||
return '<br>'.join(links)
|
||||
display_databases.short_description = _("Databases")
|
||||
display_databases.allow_tags = True
|
||||
display_databases.admin_order_field = 'databases__name'
|
||||
|
||||
def get_urls(self):
|
||||
|
|
|
@ -91,7 +91,7 @@ class DatabaseCreationForm(DatabaseUserCreationForm):
|
|||
|
||||
class ReadOnlySQLPasswordHashField(ReadOnlyPasswordHashField):
|
||||
class ReadOnlyPasswordHashWidget(forms.Widget):
|
||||
def render(self, name, value, attrs):
|
||||
def render(self, name, value, attrs, renderer=None):
|
||||
original = ReadOnlyPasswordHashField.widget().render(name, value, attrs)
|
||||
if 'Invalid' not in original:
|
||||
return original
|
||||
|
|
|
@ -3,6 +3,8 @@ from django.urls import reverse
|
|||
from django.db import models
|
||||
from django.db.models.functions import Concat, Coalesce
|
||||
from django.templatetags.static import static
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -72,9 +74,8 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
def structured_name(self, domain):
|
||||
if domain.is_top:
|
||||
return domain.name
|
||||
return ' '*4 + domain.name
|
||||
return mark_safe(' '*4 + domain.name)
|
||||
structured_name.short_description = _("name")
|
||||
structured_name.allow_tags = True
|
||||
structured_name.admin_order_field = 'structured_name'
|
||||
|
||||
def display_is_top(self, domain):
|
||||
|
@ -83,6 +84,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
display_is_top.boolean = True
|
||||
display_is_top.admin_order_field = 'top'
|
||||
|
||||
@mark_safe
|
||||
def display_websites(self, domain):
|
||||
if apps.isinstalled('orchestra.contrib.websites'):
|
||||
websites = domain.websites.all()
|
||||
|
@ -92,22 +94,22 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
site_link = get_on_site_link(website.get_absolute_url())
|
||||
admin_url = change_url(website)
|
||||
title = _("Edit website")
|
||||
link = '<a href="%s" title="%s">%s %s</a>' % (
|
||||
link = format_html('<a href="{}" title="{}">{} {}</a>',
|
||||
admin_url, title, website.name, site_link)
|
||||
links.append(link)
|
||||
return '<br>'.join(links)
|
||||
add_url = reverse('admin:websites_website_add')
|
||||
add_url += '?account=%i&domains=%i' % (domain.account_id, domain.pk)
|
||||
image = '<img src="%s"></img>' % static('orchestra/images/add.png')
|
||||
add_link = '<a href="%s" title="%s">%s</a>' % (
|
||||
add_url, _("Add website"), image
|
||||
add_link = format_html(
|
||||
'<a href="{}" title="{}"><img src="{}" /></a>', add_url,
|
||||
_("Add website"), static('orchestra/images/add.png'),
|
||||
)
|
||||
return _("No website %s") % (add_link)
|
||||
return '---'
|
||||
display_websites.admin_order_field = 'websites__name'
|
||||
display_websites.short_description = _("Websites")
|
||||
display_websites.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def display_addresses(self, domain):
|
||||
if apps.isinstalled('orchestra.contrib.mailboxes'):
|
||||
add_url = reverse('admin:mailboxes_address_add')
|
||||
|
@ -126,10 +128,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
return '---'
|
||||
display_addresses.short_description = _("Addresses")
|
||||
display_addresses.admin_order_field = 'addresses__count'
|
||||
display_addresses.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def implicit_records(self, domain):
|
||||
defaults = []
|
||||
types = set(domain.records.values_list('type', flat=True))
|
||||
ttl = settings.DOMAINS_DEFAULT_TTL
|
||||
lines = []
|
||||
|
@ -141,14 +142,13 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
value=record.value
|
||||
)
|
||||
if not domain.record_is_implicit(record, types):
|
||||
line = '<strike>%s</strike>' % line
|
||||
line = format_html('<strike>{}</strike>', line)
|
||||
if record.type is Record.SOA:
|
||||
lines.insert(0, line)
|
||||
else:
|
||||
lines.append(line)
|
||||
return '<br>'.join(lines)
|
||||
implicit_records.short_description = _("Implicit records")
|
||||
implicit_records.allow_tags = True
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
""" Add SOA fields when domain is top """
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse, NoReverseMatch
|
||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.admin.utils import unquote
|
||||
from django.contrib.admin.templatetags.admin_static import static
|
||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||
from django.contrib.admin.utils import unquote
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin.utils import admin_link, admin_date
|
||||
from orchestra.admin.utils import admin_date, admin_link
|
||||
|
||||
|
||||
class LogEntryAdmin(admin.ModelAdmin):
|
||||
|
@ -34,11 +36,12 @@ class LogEntryAdmin(admin.ModelAdmin):
|
|||
user_link = admin_link('user')
|
||||
display_action_time = admin_date('action_time', short_description=_("Time"))
|
||||
|
||||
@mark_safe
|
||||
def display_message(self, log):
|
||||
edit = '<a href="%(url)s"><img src="%(img)s"></img></a>' % {
|
||||
edit = format_html('<a href="{url}"><img src="{img}"></img></a>', **{
|
||||
'url': reverse('admin:admin_logentry_change', args=(log.pk,)),
|
||||
'img': static('admin/img/icon-changelink.svg'),
|
||||
}
|
||||
})
|
||||
if log.is_addition():
|
||||
return _('Added "%(link)s". %(edit)s') % {
|
||||
'link': self.content_object_link(log),
|
||||
|
@ -57,7 +60,6 @@ class LogEntryAdmin(admin.ModelAdmin):
|
|||
}
|
||||
display_message.short_description = _("Message")
|
||||
display_message.admin_order_field = 'action_flag'
|
||||
display_message.allow_tags = True
|
||||
|
||||
def display_action(self, log):
|
||||
if log.is_addition():
|
||||
|
@ -75,10 +77,9 @@ class LogEntryAdmin(admin.ModelAdmin):
|
|||
url = reverse(view, args=(log.object_id,))
|
||||
except NoReverseMatch:
|
||||
return log.object_repr
|
||||
return '<a href="%s">%s</a>' % (url, log.object_repr)
|
||||
return format_html('<a href="{}">{}</a>', url, log.object_repr)
|
||||
content_object_link.short_description = _("Content object")
|
||||
content_object_link.admin_order_field = 'object_repr'
|
||||
content_object_link.allow_tags = True
|
||||
|
||||
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
||||
""" Add rel_opts and object to context """
|
||||
|
|
|
@ -5,7 +5,8 @@ from django.urls import reverse
|
|||
from django.db import models
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.html import format_html, strip_tags
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from markdown import markdown
|
||||
|
||||
|
@ -50,6 +51,7 @@ class MessageReadOnlyInline(admin.TabularInline):
|
|||
'all': ('orchestra/css/hide-inline-id.css',)
|
||||
}
|
||||
|
||||
@mark_safe
|
||||
def content_html(self, msg):
|
||||
context = {
|
||||
'number': msg.number,
|
||||
|
@ -58,12 +60,13 @@ class MessageReadOnlyInline(admin.TabularInline):
|
|||
}
|
||||
summary = _("#%(number)i Updated by %(author)s about %(time)s") % context
|
||||
header = '<strong style="color:#666;">%s</strong><hr />' % summary
|
||||
|
||||
content = markdown(msg.content)
|
||||
content = content.replace('>\n', '>')
|
||||
content = '<div style="padding-left:20px;">%s</div>' % content
|
||||
|
||||
return header + content
|
||||
content_html.short_description = _("Content")
|
||||
content_html.allow_tags = True
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
@ -111,10 +114,10 @@ class TicketInline(admin.TabularInline):
|
|||
colored_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||
colored_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||
|
||||
@mark_safe
|
||||
def ticket_id(self, instance):
|
||||
return '<b>%s</b>' % admin_link()(instance)
|
||||
ticket_id.short_description = '#'
|
||||
ticket_id.allow_tags = True
|
||||
|
||||
|
||||
class TicketAdmin(ExtendedModelAdmin):
|
||||
|
@ -192,6 +195,7 @@ class TicketAdmin(ExtendedModelAdmin):
|
|||
display_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||
display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||
|
||||
@mark_safe
|
||||
def display_summary(self, ticket):
|
||||
context = {
|
||||
'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name,
|
||||
|
@ -207,14 +211,12 @@ class TicketAdmin(ExtendedModelAdmin):
|
|||
context['updated'] = '. Updated by %(updater)s about %(updated)s' % context
|
||||
return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
|
||||
display_summary.short_description = 'Summary'
|
||||
display_summary.allow_tags = True
|
||||
|
||||
def unbold_id(self, ticket):
|
||||
""" Unbold id if ticket is read """
|
||||
if ticket.is_read_by(self.user):
|
||||
return '<span style="font-weight:normal;font-size:11px;">%s</span>' % ticket.pk
|
||||
return format_html('<span style="font-weight:normal;font-size:11px;">{}</span>', ticket.pk)
|
||||
return ticket.pk
|
||||
unbold_id.allow_tags = True
|
||||
unbold_id.short_description = "#"
|
||||
unbold_id.admin_order_field = 'id'
|
||||
|
||||
|
@ -222,8 +224,7 @@ class TicketAdmin(ExtendedModelAdmin):
|
|||
""" Bold subject when tickets are unread for request.user """
|
||||
if ticket.is_read_by(self.user):
|
||||
return ticket.subject
|
||||
return "<strong class='unread'>%s</strong>" % ticket.subject
|
||||
bold_subject.allow_tags = True
|
||||
return format_html("<strong class='unread'>{}</strong>", ticket.subject)
|
||||
bold_subject.short_description = _("Subject")
|
||||
bold_subject.admin_order_field = 'subject'
|
||||
|
||||
|
@ -297,10 +298,9 @@ class QueueAdmin(admin.ModelAdmin):
|
|||
num = queue.tickets__count
|
||||
url = reverse('admin:issues_ticket_changelist')
|
||||
url += '?queue=%i' % queue.pk
|
||||
return '<a href="%s">%d</a>' % (url, num)
|
||||
return format_html('<a href="{}">{}</a>', url, num)
|
||||
num_tickets.short_description = _("Tickets")
|
||||
num_tickets.admin_order_field = 'tickets__count'
|
||||
num_tickets.allow_tags = True
|
||||
|
||||
def get_list_display(self, request):
|
||||
""" show notifications """
|
||||
|
|
|
@ -22,7 +22,7 @@ class MarkDownWidget(forms.Textarea):
|
|||
)
|
||||
markdown_help_text = 'HTML not allowed, you can use %s' % markdown_help_text
|
||||
|
||||
def render(self, name, value, attrs):
|
||||
def render(self, name, value, attrs, renderer=None):
|
||||
widget_id = attrs['id'] if attrs and 'id' in attrs else 'id_%s' % name
|
||||
textarea = super(MarkDownWidget, self).render(name, value, attrs)
|
||||
preview = ('<a class="load-preview" href="#" data-field="{0}">preview</a>'\
|
||||
|
|
|
@ -12,7 +12,7 @@ from .models import List
|
|||
|
||||
class RelatedDomainSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = List.address_domain.field.model
|
||||
model = List.address_domain.field.related_model
|
||||
fields = ('url', 'id', 'name')
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.contrib import admin, messages
|
|||
from django.urls import reverse
|
||||
from django.db.models import F, Count, Value as V
|
||||
from django.db.models.functions import Concat
|
||||
from django.utils.html import format_html, format_html_join
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -82,6 +83,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
|||
if settings.MAILBOXES_LOCAL_DOMAIN:
|
||||
type(self).actions = self.actions + (SendMailboxEmail(),)
|
||||
|
||||
@mark_safe
|
||||
def display_addresses(self, mailbox):
|
||||
# Get from forwards
|
||||
cache = caches.get_request_cache()
|
||||
|
@ -93,7 +95,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
|||
qs = qs.values_list('id', 'email', 'forward')
|
||||
for addr_id, email, mbox in qs:
|
||||
url = reverse('admin:mailboxes_address_change', args=(addr_id,))
|
||||
link = '<a href="%s">%s</a>' % (url, email)
|
||||
link = format_html('<a href="{}">{}</a>', url, email)
|
||||
try:
|
||||
cached_forwards[mbox].append(link)
|
||||
except KeyError:
|
||||
|
@ -107,26 +109,23 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
|||
addresses = []
|
||||
for addr in mailbox.addresses.all():
|
||||
url = change_url(addr)
|
||||
addresses.append('<a href="%s">%s</a>' % (url, addr.email))
|
||||
addresses.append(format_html('<a href="{}">{}</a>', url, addr.email))
|
||||
return '<br>'.join(addresses+forwards)
|
||||
display_addresses.short_description = _("Addresses")
|
||||
display_addresses.allow_tags = True
|
||||
|
||||
def display_forwards(self, mailbox):
|
||||
forwards = []
|
||||
for addr in mailbox.get_forwards():
|
||||
url = change_url(addr)
|
||||
forwards.append('<a href="%s">%s</a>' % (url, addr.email))
|
||||
return '<br>'.join(forwards)
|
||||
forwards = mailbox.get_forwards()
|
||||
return format_html_join(
|
||||
'<br>', '<a href="{}">{}</a>',
|
||||
[(change_url(addr), addr.email) for addr in forwards]
|
||||
)
|
||||
display_forwards.short_description = _("Forward from")
|
||||
display_forwards.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def display_filtering(self, mailbox):
|
||||
""" becacuse of allow_tags = True """
|
||||
return mailbox.get_filtering_display()
|
||||
display_filtering.short_description = _("Filtering")
|
||||
display_filtering.admin_order_field = 'filtering'
|
||||
display_filtering.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
if db_field.name == 'filtering':
|
||||
|
@ -217,7 +216,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
|||
elif obj.custom_filtering:
|
||||
messages.warning(request, msg)
|
||||
super(MailboxAdmin, self).save_model(request, obj, form, change)
|
||||
obj.addresses = form.cleaned_data['addresses']
|
||||
obj.addresses.set(form.cleaned_data['addresses'])
|
||||
|
||||
|
||||
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||
|
@ -247,29 +246,27 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
|
||||
def email_link(self, address):
|
||||
link = self.domain_link(address)
|
||||
return "%s@%s" % (address.name, link)
|
||||
return format_html("{}@{}", address.name, link)
|
||||
email_link.short_description = _("Email")
|
||||
email_link.allow_tags = True
|
||||
|
||||
def display_mailboxes(self, address):
|
||||
boxes = []
|
||||
for mailbox in address.mailboxes.all():
|
||||
url = change_url(mailbox)
|
||||
boxes.append('<a href="%s">%s</a>' % (url, mailbox.name))
|
||||
return '<br>'.join(boxes)
|
||||
boxes = address.mailboxes.all()
|
||||
return format_html_join(
|
||||
'<br>', '<a href="{}">{}</a>',
|
||||
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
||||
)
|
||||
display_mailboxes.short_description = _("Mailboxes")
|
||||
display_mailboxes.allow_tags = True
|
||||
display_mailboxes.admin_order_field = 'mailboxes__count'
|
||||
|
||||
def display_all_mailboxes(self, address):
|
||||
boxes = []
|
||||
for mailbox in address.get_mailboxes():
|
||||
url = change_url(mailbox)
|
||||
boxes.append('<a href="%s">%s</a>' % (url, mailbox.name))
|
||||
return '<br>'.join(boxes)
|
||||
boxes = address.get_mailboxes()
|
||||
return format_html_join(
|
||||
'<br>', '<a href="{}">{}</a>',
|
||||
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
||||
)
|
||||
display_all_mailboxes.short_description = _("Mailboxes links")
|
||||
display_all_mailboxes.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def display_forward(self, address):
|
||||
forward_mailboxes = {m.name: m for m in address.get_forward_mailboxes()}
|
||||
values = []
|
||||
|
@ -281,7 +278,6 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
values.append(forward)
|
||||
return '<br>'.join(values)
|
||||
display_forward.short_description = _("Forward")
|
||||
display_forward.allow_tags = True
|
||||
display_forward.admin_order_field = 'forward'
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
|
|
|
@ -44,7 +44,7 @@ class Mailbox(models.Model):
|
|||
def active(self):
|
||||
try:
|
||||
return self.is_active and self.account.is_active
|
||||
except type(self).account.field.model.DoesNotExist:
|
||||
except type(self).account.field.related_model.DoesNotExist:
|
||||
return self.is_active
|
||||
|
||||
def disable(self):
|
||||
|
|
|
@ -6,6 +6,8 @@ from django.contrib import admin
|
|||
from django.urls import reverse
|
||||
from django.db.models import Count
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -60,11 +62,10 @@ class MessageAdmin(ExtendedModelAdmin):
|
|||
def display_subject(self, instance):
|
||||
subject = instance.subject
|
||||
if len(subject) > 64:
|
||||
return subject[:64] + '…'
|
||||
return mark_safe(subject[:64] + '…')
|
||||
return subject
|
||||
display_subject.short_description = _("Subject")
|
||||
display_subject.admin_order_field = 'subject'
|
||||
display_subject.allow_tags = True
|
||||
|
||||
def display_retries(self, instance):
|
||||
num_logs = instance.logs__count
|
||||
|
@ -74,10 +75,9 @@ class MessageAdmin(ExtendedModelAdmin):
|
|||
else:
|
||||
url = reverse('admin:mailer_smtplog_changelist')
|
||||
url += '?&message=%i' % instance.pk
|
||||
return '<a href="%s" onclick="return showAddAnotherPopup(this);">%d</a>' % (url, instance.retries)
|
||||
return format_html('<a href="{}" onclick="return showAddAnotherPopup(this);">{}</a>', url, instance.retries)
|
||||
display_retries.short_description = _("Retries")
|
||||
display_retries.admin_order_field = 'retries'
|
||||
display_retries.allow_tags = True
|
||||
|
||||
def display_content(self, instance):
|
||||
part = email.message_from_string(instance.content)
|
||||
|
@ -99,9 +99,8 @@ class MessageAdmin(ExtendedModelAdmin):
|
|||
payload = payload.decode(charset)
|
||||
if part.get_content_type() == 'text/plain':
|
||||
payload = payload.replace('\n', '<br>').replace(' ', ' ')
|
||||
return payload
|
||||
return mark_safe(payload)
|
||||
display_content.short_description = _("Content")
|
||||
display_content.allow_tags = True
|
||||
|
||||
def display_full_subject(self, instance):
|
||||
return instance.subject
|
||||
|
|
|
@ -2,6 +2,7 @@ from django import forms
|
|||
from django.contrib import admin
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -38,15 +39,13 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
|||
actions = (disable, enable)
|
||||
|
||||
def display_name(self, misc):
|
||||
return '<span title="%s">%s</span>' % (misc.description, misc.name)
|
||||
return format_html('<span title="{}">{}</span>', misc.description, misc.name)
|
||||
display_name.short_description = _("name")
|
||||
display_name.allow_tags = True
|
||||
display_name.admin_order_field = 'name'
|
||||
|
||||
def display_verbose_name(self, misc):
|
||||
return '<span title="%s">%s</span>' % (misc.description, misc.verbose_name)
|
||||
return format_html('<span title="{}">{}</span>', misc.description, misc.verbose_name)
|
||||
display_verbose_name.short_description = _("verbose name")
|
||||
display_verbose_name.allow_tags = True
|
||||
display_verbose_name.admin_order_field = 'verbose_name'
|
||||
|
||||
def num_instances(self, misc):
|
||||
|
|
|
@ -51,19 +51,18 @@ class RouteAdmin(ExtendedModelAdmin):
|
|||
|
||||
def display_model(self, route):
|
||||
try:
|
||||
return escape(route.backend_class.model)
|
||||
return route.backend_class.model
|
||||
except KeyError:
|
||||
return "<span style='color: red;'>NOT AVAILABLE</span>"
|
||||
return mark_safe("<span style='color: red;'>NOT AVAILABLE</span>")
|
||||
display_model.short_description = _("model")
|
||||
display_model.allow_tags = True
|
||||
|
||||
@mark_safe
|
||||
def display_actions(self, route):
|
||||
try:
|
||||
return '<br>'.join(route.backend_class.get_actions())
|
||||
except KeyError:
|
||||
return "<span style='color: red;'>NOT AVAILABLE</span>"
|
||||
display_actions.short_description = _("actions")
|
||||
display_actions.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Provides dynamic help text on backend form field """
|
||||
|
@ -120,7 +119,6 @@ class BackendOperationInline(admin.TabularInline):
|
|||
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
||||
(escape(operation.content_type), escape(operation.object_id))))
|
||||
return link
|
||||
instance_link.allow_tags = True
|
||||
instance_link.short_description = _("Instance")
|
||||
|
||||
def has_add_permission(self, *args, **kwargs):
|
||||
|
@ -179,14 +177,12 @@ class ServerAdmin(ExtendedModelAdmin):
|
|||
change_view_actions = actions
|
||||
|
||||
def display_ping(self, instance):
|
||||
return self._remote_state[instance.pk][0]
|
||||
return mark_safe(self._remote_state[instance.pk][0])
|
||||
display_ping.short_description = _("Ping")
|
||||
display_ping.allow_tags = True
|
||||
|
||||
def display_uptime(self, instance):
|
||||
return self._remote_state[instance.pk][1]
|
||||
return mark_safe(self._remote_state[instance.pk][1])
|
||||
display_uptime.short_description = _("Uptime")
|
||||
display_uptime.allow_tags = True
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Order by structured name and imporve performance """
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
|
||||
from orchestra.forms.widgets import SpanWidget, paddingCheckboxSelectMultiple
|
||||
from orchestra.forms.widgets import SpanWidget, PaddingCheckboxSelectMultiple
|
||||
|
||||
|
||||
class RouteForm(forms.ModelForm):
|
||||
|
@ -16,5 +16,5 @@ class RouteForm(forms.ModelForm):
|
|||
else:
|
||||
self.fields['backend'].widget = SpanWidget()
|
||||
actions = backend_class.actions
|
||||
self.fields['async_actions'].widget = paddingCheckboxSelectMultiple(45)
|
||||
self.fields['async_actions'].widget = PaddingCheckboxSelectMultiple(45)
|
||||
self.fields['async_actions'].choices = ((action, action) for action in actions)
|
||||
|
|
|
@ -51,8 +51,9 @@ class Server(models.Model):
|
|||
|
||||
def clean(self):
|
||||
self.name = self.name.strip()
|
||||
self.address = self.address.strip()
|
||||
if self.name and not self.address:
|
||||
if self.address:
|
||||
self.address = self.address.strip()
|
||||
elif self.name:
|
||||
validate = OrValidator(validate_ip_address, validate_hostname)
|
||||
validate_hostname(self.name)
|
||||
try:
|
||||
|
|
|
@ -14,7 +14,12 @@ def retrieve_state(servers):
|
|||
state = {}
|
||||
for server, ping, uptime in zip(servers, pings, uptimes):
|
||||
ping = join(ping, silent=True)
|
||||
ping = ping.stdout.splitlines()[-1].decode()
|
||||
|
||||
try:
|
||||
ping = ping.stdout.splitlines()[-1].decode()
|
||||
except IndexError:
|
||||
ping = ''
|
||||
|
||||
if ping.startswith('rtt'):
|
||||
ping = '%s ms' % ping.split('/')[4]
|
||||
else:
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from datetime import datetime
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.urls import reverse, NoReverseMatch
|
||||
from django.db.models import Prefetch
|
||||
from django.utils import timezone
|
||||
from django.utils.html import escape
|
||||
from django.utils.html import escape, format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -112,9 +113,8 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
display_cancelled_on = admin_date('cancelled_on')
|
||||
|
||||
def display_description(self, order):
|
||||
return order.description[:64]
|
||||
return format_html(order.description[:64])
|
||||
display_description.short_description = _("Description")
|
||||
display_description.allow_tags = True
|
||||
display_description.admin_order_field = 'description'
|
||||
|
||||
def content_object_link(self, order):
|
||||
|
@ -125,13 +125,13 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
# Does not has admin
|
||||
return order.content_object_repr
|
||||
description = str(order.content_object)
|
||||
return '<a href="{url}">{description}</a>'.format(
|
||||
return format_html('<a href="{url}">{description}</a>',
|
||||
url=url, description=description)
|
||||
return order.content_object_repr
|
||||
content_object_link.short_description = _("Content object")
|
||||
content_object_link.allow_tags = True
|
||||
content_object_link.admin_order_field = 'content_object_repr'
|
||||
|
||||
@mark_safe
|
||||
def bills_links(self, order):
|
||||
bills = []
|
||||
make_link = admin_link()
|
||||
|
@ -139,7 +139,6 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
bills.append(make_link(line.bill))
|
||||
return '<br>'.join(bills)
|
||||
bills_links.short_description = _("Bills")
|
||||
bills_links.allow_tags = True
|
||||
|
||||
def display_billed_until(self, order):
|
||||
billed_until = order.billed_until
|
||||
|
@ -156,12 +155,12 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
red = True
|
||||
elif billed_until < timezone.now().date():
|
||||
red = True
|
||||
color = 'style="color:red;"' if red else ''
|
||||
return '<span title="{raw}" {color}>{human}</span>'.format(
|
||||
color = mark_safe('style="color:red;"') if red else ''
|
||||
return format_html(
|
||||
'<span title="{raw}" {color}>{human}</span>',
|
||||
raw=escape(str(billed_until)), color=color, human=human,
|
||||
)
|
||||
display_billed_until.short_description = _("billed until")
|
||||
display_billed_until.allow_tags = True
|
||||
display_billed_until.admin_order_field = 'billed_until'
|
||||
|
||||
def display_metric(self, order):
|
||||
|
|
|
@ -15,7 +15,7 @@ def cancel_orders(sender, **kwargs):
|
|||
if sender._meta.app_label not in settings.ORDERS_EXCLUDED_APPS:
|
||||
instance = kwargs['instance']
|
||||
# Account delete will delete all related orders, no need to maintain order consistency
|
||||
if isinstance(instance, Order.account.field.model):
|
||||
if isinstance(instance, Order.account.field.related_model):
|
||||
return
|
||||
if type(instance) in services:
|
||||
for order in Order.objects.by_object(instance).active():
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from django.contrib import admin
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeViewActionsMixin, ExtendedModelAdmin
|
||||
|
@ -154,6 +156,7 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
return []
|
||||
return [action for action in actions if action.__name__ not in exclude]
|
||||
|
||||
@mark_safe
|
||||
def display_state(self, obj):
|
||||
state = admin_colored('state', colors=STATE_COLORS)(obj)
|
||||
help_text = obj.get_state_help()
|
||||
|
@ -161,7 +164,6 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
return state
|
||||
display_state.admin_order_field = 'state'
|
||||
display_state.short_description = _("State")
|
||||
display_state.allow_tags = True
|
||||
|
||||
|
||||
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||
|
@ -184,10 +186,10 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
|||
|
||||
def file_url(self, process):
|
||||
if process.file:
|
||||
return '<a href="%s">%s</a>' % (process.file.url, process.file.name)
|
||||
file_url.allow_tags = True
|
||||
return format_html('<a href="{}">{}</a>', process.file.url, process.file.name)
|
||||
file_url.admin_order_field = 'file'
|
||||
|
||||
@mark_safe
|
||||
def display_transactions(self, process):
|
||||
ids = []
|
||||
lines = []
|
||||
|
@ -207,7 +209,6 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
|||
url += '?process_id=%i' % process.id
|
||||
return '<a href="%s">%s</a>' % (url, transactions)
|
||||
display_transactions.short_description = _("Transactions")
|
||||
display_transactions.allow_tags = True
|
||||
|
||||
def has_add_permission(self, *args, **kwargs):
|
||||
return False
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from django.urls import reverse
|
||||
from django.db import models
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -33,10 +34,9 @@ class PlanAdmin(ExtendedModelAdmin):
|
|||
num = plan.contracts__count
|
||||
url = reverse('admin:plans_contractedplan_changelist')
|
||||
url += '?plan__name={}'.format(plan.name)
|
||||
return '<a href="{0}">{1}</a>'.format(url, num)
|
||||
return format_html('<a href="{0}">{1}</a>', url, num)
|
||||
num_contracts.short_description = _("Contracts")
|
||||
num_contracts.admin_order_field = 'contracts__count'
|
||||
num_contracts.allow_tags = True
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(PlanAdmin, self).get_queryset(request)
|
||||
|
|
|
@ -11,6 +11,7 @@ from django.db.models import Q
|
|||
from django.shortcuts import redirect
|
||||
from django.templatetags.static import static
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||
|
||||
|
@ -105,10 +106,9 @@ class ResourceAdmin(ExtendedModelAdmin):
|
|||
def content_object_link(data):
|
||||
ct = data.content_type
|
||||
url = reverse('admin:%s_%s_change' % (ct.app_label, ct.model), args=(data.object_id,))
|
||||
return '<a href="%s">%s</a>' % (url, data.content_object_repr)
|
||||
return format_html('<a href="{}">{}</a>', url, data.content_object_repr)
|
||||
content_object_link.short_description = _("Content object")
|
||||
content_object_link.admin_order_field = 'content_object_repr'
|
||||
content_object_link.allow_tags = True
|
||||
|
||||
|
||||
class ResourceDataAdmin(ExtendedModelAdmin):
|
||||
|
@ -155,10 +155,9 @@ class ResourceDataAdmin(ExtendedModelAdmin):
|
|||
if rdata.used is None:
|
||||
return ''
|
||||
url = reverse('admin:resources_resourcedata_used_monitordata', args=(rdata.pk,))
|
||||
return '<a href="%s">%s %s</a>' % (url, rdata.used, rdata.unit)
|
||||
return format_html('<a href="{}">{} {}</a>', url, rdata.used, rdata.unit)
|
||||
display_used.short_description = _("Used")
|
||||
display_used.admin_order_field = 'used'
|
||||
display_used.allow_tags = True
|
||||
|
||||
def has_add_permission(self, *args, **kwargs):
|
||||
return False
|
||||
|
@ -304,6 +303,7 @@ def resource_inline_factory(resources):
|
|||
self.verbose_name_plural = mark_safe(_("Resources") + ' ' + link)
|
||||
return super(ResourceInline, self).get_fieldsets(request, obj)
|
||||
|
||||
@mark_safe
|
||||
def display_used(self, rdata):
|
||||
update = ''
|
||||
history = ''
|
||||
|
@ -329,7 +329,6 @@ def resource_inline_factory(resources):
|
|||
return _("Unknonw %s %s") % (update, history)
|
||||
return _("No monitor")
|
||||
display_used.short_description = _("Used")
|
||||
display_used.allow_tags = True
|
||||
|
||||
def has_add_permission(self, *args, **kwargs):
|
||||
""" Hidde add another """
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.contrib import admin
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||
|
@ -27,6 +28,7 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
|||
plugin_title = 'Software as a Service'
|
||||
actions = (disable, enable, list_accounts)
|
||||
|
||||
@mark_safe
|
||||
def display_url(self, saas):
|
||||
site_domain = saas.get_site_domain()
|
||||
site_link = '<a href="http://%s">%s</a>' % (site_domain, site_domain)
|
||||
|
@ -46,7 +48,6 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
|||
links.append(link)
|
||||
return '<br>'.join(links)
|
||||
display_url.short_description = _("URL")
|
||||
display_url.allow_tags = True
|
||||
display_url.admin_order_field = 'name'
|
||||
|
||||
def get_fields(self, *args, **kwargs):
|
||||
|
|
|
@ -42,7 +42,7 @@ def clean_custom_url(saas):
|
|||
)
|
||||
except Website.DoesNotExist:
|
||||
# get or create domain
|
||||
Domain = Website.domains.field.model
|
||||
Domain = Website.domains.field.related_model
|
||||
try:
|
||||
domain = Domain.objects.get(name=url.netloc)
|
||||
except Domain.DoesNotExist:
|
||||
|
@ -110,7 +110,7 @@ def create_or_update_directive(saas):
|
|||
account=account,
|
||||
)
|
||||
except Website.DoesNotExist:
|
||||
Domain = Website.domains.field.model
|
||||
Domain = Website.domains.field.related_model
|
||||
domain = Domain.objects.get(name=url.netloc)
|
||||
# Create new website for custom_url
|
||||
tgt_server = Server.objects.get(name='web.pangea.lan')
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib import admin
|
|||
from django.urls import reverse
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils import timezone
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeViewActionsMixin
|
||||
|
@ -69,10 +70,9 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
|||
num = service.orders__count
|
||||
url = reverse('admin:orders_order_changelist')
|
||||
url += '?service__id__exact=%i&is_active=True' % service.pk
|
||||
return '<a href="%s">%d</a>' % (url, num)
|
||||
return format_html('<a href="{}">{}</a>', url, num)
|
||||
num_orders.short_description = _("Orders")
|
||||
num_orders.admin_order_field = 'orders__count'
|
||||
num_orders.allow_tags = True
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(ServiceAdmin, self).get_queryset(request)
|
||||
|
|
|
@ -61,7 +61,7 @@ class SystemUser(models.Model):
|
|||
def active(self):
|
||||
try:
|
||||
return self.is_active and self.account.is_active
|
||||
except type(self).account.field.model.DoesNotExist:
|
||||
except type(self).account.field.related_model.DoesNotExist:
|
||||
return self.is_active
|
||||
|
||||
@cached_property
|
||||
|
|
|
@ -2,6 +2,7 @@ from django import forms
|
|||
from django.contrib import admin
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -66,6 +67,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
|||
|
||||
display_type = display_plugin_field('type')
|
||||
|
||||
@mark_safe
|
||||
def display_websites(self, webapp):
|
||||
websites = []
|
||||
for content in webapp.content_set.all():
|
||||
|
@ -82,29 +84,13 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
|||
websites.append('<a href="%s">%s%s</a>' % (add_url, plus, ugettext("Add website")))
|
||||
return '<br>'.join(websites)
|
||||
display_websites.short_description = _("web sites")
|
||||
display_websites.allow_tags = True
|
||||
|
||||
def display_detail(self, webapp):
|
||||
try:
|
||||
return webapp.type_instance.get_detail()
|
||||
except KeyError:
|
||||
return "<span style='color:red;'>Not available</span>"
|
||||
return mark_safe("<span style='color:red;'>Not available</span>")
|
||||
display_detail.short_description = _("detail")
|
||||
display_detail.allow_tags = True
|
||||
|
||||
# def get_form(self, request, obj=None, **kwargs):
|
||||
# form = super(WebAppAdmin, self).get_form(request, obj, **kwargs)
|
||||
# if obj:
|
||||
#
|
||||
|
||||
# def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
# """ Make value input widget bigger """
|
||||
# if db_field.name == 'type':
|
||||
# # Help text based on select widget
|
||||
# kwargs['widget'] = DynamicHelpTextSelect(
|
||||
# 'this.id.replace("name", "value")', self.TYPE_HELP_TEXT
|
||||
# )
|
||||
# kwargs['help_text'] = self.TYPE_HELP_TEXT.get(db_field.default, '')
|
||||
# return super(WebAppAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
admin.site.register(WebApp, WebAppAdmin)
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import textwrap
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.template import Template, Context
|
||||
from django.template import Template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.contrib.orchestration import ServiceController
|
||||
|
@ -245,7 +245,7 @@ class PHPController(WebAppServiceMixin, ServiceController):
|
|||
php_admin_value[{{ name | safe }}] = {{ value | safe }}{% endfor %}
|
||||
"""
|
||||
))
|
||||
return fpm_config.render(Context(context))
|
||||
return fpm_config.render(context)
|
||||
|
||||
def get_fcgid_wrapper(self, webapp, context):
|
||||
opt = webapp.type_instance
|
||||
|
|
|
@ -3,6 +3,8 @@ from django.contrib import admin
|
|||
from django.urls import resolve
|
||||
from django.db.models import Q
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
|
@ -78,6 +80,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
search_fields = ('name', 'account__username', 'domains__name', 'content__webapp__name')
|
||||
actions = (disable, enable, list_accounts)
|
||||
|
||||
@mark_safe
|
||||
def display_domains(self, website):
|
||||
domains = []
|
||||
for domain in website.domains.all():
|
||||
|
@ -85,9 +88,9 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
domains.append('<a href="%s">%s</a>' % (url, url))
|
||||
return '<br>'.join(domains)
|
||||
display_domains.short_description = _("domains")
|
||||
display_domains.allow_tags = True
|
||||
display_domains.admin_order_field = 'domains'
|
||||
|
||||
@mark_safe
|
||||
def display_webapps(self, website):
|
||||
webapps = []
|
||||
for content in website.content_set.all():
|
||||
|
@ -100,9 +103,9 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
pass
|
||||
url = change_url(webapp)
|
||||
name = "%s on %s" % (webapp.name, content.path or '/')
|
||||
webapps.append('<a href="%s" title="%s">%s %s</a>' % (url, detail, name, site_link))
|
||||
webapp_info = format_html('<a href="{}" title="{}">{}</a> {}', url, detail, name, site_link)
|
||||
webapps.append(webapp_info)
|
||||
return '<br>'.join(webapps)
|
||||
display_webapps.allow_tags = True
|
||||
display_webapps.short_description = _("Web apps")
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import re
|
||||
import textwrap
|
||||
|
||||
from django.template import Template, Context
|
||||
from django.template import Template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.contrib.orchestration import ServiceController
|
||||
|
@ -78,7 +78,7 @@ class Apache2Controller(ServiceController):
|
|||
{{ line | safe }}{% endfor %}
|
||||
</VirtualHost>
|
||||
""")
|
||||
).render(Context(context))
|
||||
).render(context)
|
||||
|
||||
def render_redirect_https(self, context):
|
||||
context['port'] = self.HTTP_PORT
|
||||
|
@ -96,7 +96,7 @@ class Apache2Controller(ServiceController):
|
|||
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
||||
</VirtualHost>
|
||||
""")
|
||||
).render(Context(context))
|
||||
).render(context)
|
||||
|
||||
def save(self, site):
|
||||
context = self.get_context(site)
|
||||
|
|
|
@ -13,13 +13,13 @@ from .validators import validate_domain_protocol
|
|||
|
||||
class RelatedDomainSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Website.domains.field.model
|
||||
model = Website.domains.field.related_model
|
||||
fields = ('url', 'id', 'name')
|
||||
|
||||
|
||||
class RelatedWebAppSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Content.webapp.field.model
|
||||
model = Content.webapp.field.related_model
|
||||
fields = ('url', 'id', 'name', 'type')
|
||||
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ class SpanWidget(forms.Widget):
|
|||
self.display = kwargs.pop('display', None)
|
||||
super(SpanWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
final_attrs = self.build_attrs(attrs, name=name)
|
||||
def render(self, name, value, attrs=None, renderer=None):
|
||||
final_attrs = self.build_attrs(attrs, extra_attrs={'name':name})
|
||||
original = self.original or value
|
||||
display = original if self.display is None else self.display
|
||||
# Display icon
|
||||
|
@ -37,17 +37,17 @@ class SpanWidget(forms.Widget):
|
|||
return False
|
||||
|
||||
|
||||
def paddingCheckboxSelectMultiple(padding):
|
||||
class PaddingCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
||||
""" Ugly hack to render this widget nicely on Django admin """
|
||||
widget = forms.CheckboxSelectMultiple()
|
||||
old_render = widget.render
|
||||
def __init__(self, padding, attrs=None, choices=()):
|
||||
super().__init__(attrs=attrs, choices=choices)
|
||||
self.padding = padding
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
value = old_render(self, *args, **kwargs)
|
||||
value = super().render(*args, **kwargs)
|
||||
value = re.sub(r'^<ul id=([^>]+)>',
|
||||
r'<ul id=\1 style="padding-left:%ipx">' % padding, value, 1)
|
||||
r'<ul id=\1 style="padding-left:%ipx">' % self.padding, value, 1)
|
||||
return mark_safe(value)
|
||||
widget.render = render
|
||||
return widget
|
||||
|
||||
|
||||
class DynamicHelpTextSelect(forms.Select):
|
||||
|
|
|
@ -90,7 +90,7 @@ class RelatedPermission(Permission):
|
|||
if obj is None:
|
||||
parent = cls
|
||||
for relation in relations:
|
||||
parent = getattr(parent, relation).field.model
|
||||
parent = getattr(parent, relation).field.related_model
|
||||
else:
|
||||
parent = functools.reduce(getattr, relations, obj)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import textwrap
|
||||
|
||||
from django.templatetags.static import static
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.utils.sys import run
|
||||
|
@ -31,6 +32,6 @@ def get_on_site_link(url):
|
|||
context = {
|
||||
'title': _("View on site %s") % url,
|
||||
'url': url,
|
||||
'image': '<img src="%s"></img>' % static('orchestra/images/view-on-site.png'),
|
||||
'image': format_html('<img src="{}"></img>', static('orchestra/images/view-on-site.png')),
|
||||
}
|
||||
return '<a href="%(url)s" title="%(title)s">%(image)s</a>' % context
|
||||
return format_html('<a href="{url}" title="{title}">{image}</a>', **context)
|
||||
|
|
|
@ -2,7 +2,6 @@ from urllib.parse import urlparse
|
|||
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import Context
|
||||
|
||||
|
||||
def render_email_template(template, context):
|
||||
|
@ -11,11 +10,8 @@ def render_email_template(template, context):
|
|||
{% if subject %}Subject{% endif %}
|
||||
{% if message %}Email body{% endif %}
|
||||
|
||||
context can be a dictionary or a template.Context instance
|
||||
context must be a dict
|
||||
"""
|
||||
if isinstance(context, dict):
|
||||
context = Context(context)
|
||||
|
||||
if not 'site' in context:
|
||||
from orchestra import settings
|
||||
url = urlparse(settings.ORCHESTRA_SITE_URL)
|
||||
|
|
|
@ -12,7 +12,7 @@ ecdsa==0.11
|
|||
Pygments==1.6
|
||||
django-filter==2.2.0
|
||||
jsonfield==0.9.22
|
||||
python-dateutil==2.2
|
||||
python-dateutil>=2.7.0
|
||||
https://github.com/glic3rinu/passlib/archive/master.zip
|
||||
django-iban==0.3.0
|
||||
requests
|
||||
|
|
Loading…
Reference in New Issue