WIP: django-3.2-compat #3
|
@ -1,12 +1,13 @@
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.mail import send_mass_mail
|
from django.core.mail import send_mass_mail
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.translation import ngettext, gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils.translation import ngettext
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
|
||||||
from .decorators import action_with_confirmation
|
from .decorators import action_with_confirmation
|
||||||
from .forms import SendEmailForm
|
from .forms import SendEmailForm
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ class SendEmail(object):
|
||||||
|
|
||||||
def write_email(self, request):
|
def write_email(self, request):
|
||||||
if not request.user.is_superuser:
|
if not request.user.is_superuser:
|
||||||
raise PermissionDenied
|
raise PermissionDenied()
|
||||||
initial={
|
initial={
|
||||||
'email_from': self.default_from,
|
'email_from': self.default_from,
|
||||||
'to': ' '.join(self.get_email_addresses())
|
'to': ' '.join(self.get_email_addresses())
|
||||||
|
@ -131,15 +132,19 @@ def base_disable(modeladmin, request, queryset, disable=True):
|
||||||
modeladmin.message_user(request, msg)
|
modeladmin.message_user(request, msg)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(
|
||||||
|
description=_("Disable")
|
||||||
|
)
|
||||||
@action_with_confirmation()
|
@action_with_confirmation()
|
||||||
def disable(modeladmin, request, queryset):
|
def disable(modeladmin, request, queryset):
|
||||||
return base_disable(modeladmin, request, queryset)
|
return base_disable(modeladmin, request, queryset)
|
||||||
disable.url_name = 'disable'
|
disable.url_name = 'disable'
|
||||||
disable.short_description = _("Disable")
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(
|
||||||
|
description=_("Enable")
|
||||||
|
)
|
||||||
@action_with_confirmation()
|
@action_with_confirmation()
|
||||||
def enable(modeladmin, request, queryset):
|
def enable(modeladmin, request, queryset):
|
||||||
return base_disable(modeladmin, request, queryset, disable=False)
|
return base_disable(modeladmin, request, queryset, disable=False)
|
||||||
enable.url_name = 'enable'
|
enable.url_name = 'enable'
|
||||||
enable.short_description = _("Enable")
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.urls import re_path as url
|
|
||||||
from django.contrib import admin, messages
|
from django.contrib import admin, messages
|
||||||
from django.contrib.admin.options import IS_POPUP_VAR
|
from django.contrib.admin.options import IS_POPUP_VAR
|
||||||
from django.contrib.admin.utils import unquote
|
from django.contrib.admin.utils import unquote
|
||||||
from django.contrib.auth import update_session_auth_hash
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.http import HttpResponseRedirect, Http404, HttpResponse
|
|
||||||
from django.forms.models import BaseInlineFormSet
|
from django.forms.models import BaseInlineFormSet
|
||||||
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.urls import re_path as url
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
|
@ -19,14 +19,12 @@ from django.views.decorators.debug import sensitive_post_parameters
|
||||||
|
|
||||||
from orchestra.models.utils import has_db_field
|
from orchestra.models.utils import has_db_field
|
||||||
|
|
||||||
from ..utils.python import random_ascii, pairwise
|
from ..utils.python import pairwise, random_ascii
|
||||||
|
|
||||||
from .forms import AdminPasswordChangeForm
|
from .forms import AdminPasswordChangeForm
|
||||||
#, AdminRawPasswordChangeForm
|
#, AdminRawPasswordChangeForm
|
||||||
#from django.contrib.auth.forms import AdminPasswordChangeForm
|
#from django.contrib.auth.forms import AdminPasswordChangeForm
|
||||||
from .utils import action_to_view
|
from .utils import action_to_view
|
||||||
|
|
||||||
|
|
||||||
sensitive_post_parameters_m = method_decorator(sensitive_post_parameters())
|
sensitive_post_parameters_m = method_decorator(sensitive_post_parameters())
|
||||||
|
|
||||||
|
|
||||||
|
@ -256,7 +254,7 @@ class ChangePasswordAdminMixin(object):
|
||||||
@sensitive_post_parameters_m
|
@sensitive_post_parameters_m
|
||||||
def change_password(self, request, id, form_url=''):
|
def change_password(self, request, id, form_url=''):
|
||||||
if not self.has_change_permission(request):
|
if not self.has_change_permission(request):
|
||||||
raise PermissionDenied
|
raise PermissionDenied()
|
||||||
# TODO use this insetad of self.get_object(), in other places
|
# TODO use this insetad of self.get_object(), in other places
|
||||||
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
||||||
raw = request.GET.get('raw', '0') == '1'
|
raw = request.GET.get('raw', '0') == '1'
|
||||||
|
@ -334,6 +332,6 @@ class ChangePasswordAdminMixin(object):
|
||||||
|
|
||||||
def show_hash(self, request, id):
|
def show_hash(self, request, id):
|
||||||
if not request.user.is_superuser:
|
if not request.user.is_superuser:
|
||||||
raise PermissionDenied
|
raise PermissionDenied()
|
||||||
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
obj = get_object_or_404(self.get_queryset(request), pk=id)
|
||||||
return HttpResponse(obj.password)
|
return HttpResponse(obj.password)
|
||||||
|
|
|
@ -145,6 +145,8 @@ DATABASES = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#auth-password-validators
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.conf.urls import include, url
|
from django.urls import include, path
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'', include('orchestra.urls')),
|
path('', include('orchestra.urls')),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.accounts.apps.AccountConfig'
|
|
|
@ -29,6 +29,7 @@ from .models import Account
|
||||||
from .filters import HasTipeServerFilter
|
from .filters import HasTipeServerFilter
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Account)
|
||||||
class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'full_name', 'type', 'is_active')
|
list_display = ('username', 'full_name', 'type', 'is_active')
|
||||||
list_filter = (
|
list_filter = (
|
||||||
|
@ -150,7 +151,6 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Account, AccountAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
class AccountListAdmin(AccountAdmin):
|
class AccountListAdmin(AccountAdmin):
|
||||||
|
@ -159,6 +159,10 @@ class AccountListAdmin(AccountAdmin):
|
||||||
actions = None
|
actions = None
|
||||||
change_list_template = 'admin/accounts/account/select_account_list.html'
|
change_list_template = 'admin/accounts/account/select_account_list.html'
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("account"),
|
||||||
|
ordering='username',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def select_account(self, instance):
|
def select_account(self, instance):
|
||||||
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
||||||
|
@ -168,8 +172,6 @@ class AccountListAdmin(AccountAdmin):
|
||||||
'plus': '<strong style="color:green; font-size:12px">+</strong>',
|
'plus': '<strong style="color:green; font-size:12px">+</strong>',
|
||||||
}
|
}
|
||||||
return _('<a href="%(url)s">%(plus)s Add to %(name)s</a>') % context
|
return _('<a href="%(url)s">%(plus)s Add to %(name)s</a>') % context
|
||||||
select_account.short_description = _("account")
|
|
||||||
select_account.admin_order_field = 'username'
|
|
||||||
|
|
||||||
def changelist_view(self, request, extra_context=None):
|
def changelist_view(self, request, extra_context=None):
|
||||||
app_label = request.META['PATH_INFO'].split('/')[-5]
|
app_label = request.META['PATH_INFO'].split('/')[-5]
|
||||||
|
@ -208,6 +210,10 @@ class AccountAdminMixin(object):
|
||||||
account = None
|
account = None
|
||||||
list_select_related = ('account',)
|
list_select_related = ('account',)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("active"),
|
||||||
|
ordering='is_active',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_active(self, instance):
|
def display_active(self, instance):
|
||||||
if not instance.is_active:
|
if not instance.is_active:
|
||||||
|
@ -216,14 +222,14 @@ class AccountAdminMixin(object):
|
||||||
msg = _("Account disabled")
|
msg = _("Account disabled")
|
||||||
return '<img style="width:13px" src="%s" alt="False" title="%s">' % (static('admin/img/inline-delete.svg'), msg)
|
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')
|
return '<img src="%s" alt="False">' % static('admin/img/icon-yes.svg')
|
||||||
display_active.short_description = _("active")
|
|
||||||
display_active.admin_order_field = 'is_active'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("account"),
|
||||||
|
ordering='account__username',
|
||||||
|
)
|
||||||
def account_link(self, instance):
|
def account_link(self, instance):
|
||||||
account = instance.account if instance.pk else self.account
|
account = instance.account if instance.pk else self.account
|
||||||
return admin_link()(account)
|
return admin_link()(account)
|
||||||
account_link.short_description = _("account")
|
|
||||||
account_link.admin_order_field = 'account__username'
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
""" Warns user when object's account is disabled """
|
""" Warns user when object's account is disabled """
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.bills.apps.BillsConfig'
|
|
|
@ -68,6 +68,9 @@ class BillLineInline(admin.TabularInline):
|
||||||
|
|
||||||
order_link = admin_link('order', display='pk')
|
order_link = admin_link('order', display='pk')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Total")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_total(self, line):
|
def display_total(self, line):
|
||||||
if line.pk:
|
if line.pk:
|
||||||
|
@ -79,7 +82,6 @@ class BillLineInline(admin.TabularInline):
|
||||||
img = static('admin/img/icon-alert.svg')
|
img = static('admin/img/icon-alert.svg')
|
||||||
return '<a href="%s" title="%s">%s <img src="%s"></img></a>' % (url, content, total, img)
|
return '<a href="%s" title="%s">%s <img src="%s"></img></a>' % (url, content, total, img)
|
||||||
return '<a href="%s">%s</a>' % (url, total)
|
return '<a href="%s">%s</a>' % (url, total)
|
||||||
display_total.short_description = _("Total")
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -105,31 +107,38 @@ class ClosedBillLineInline(BillLineInline):
|
||||||
readonly_fields = fields
|
readonly_fields = fields
|
||||||
can_delete = False
|
can_delete = False
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Description")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_description(self, line):
|
def display_description(self, line):
|
||||||
descriptions = [line.description]
|
descriptions = [line.description]
|
||||||
for subline in line.sublines.all():
|
for subline in line.sublines.all():
|
||||||
descriptions.append(' ' * 4 + subline.description)
|
descriptions.append(' ' * 4 + subline.description)
|
||||||
return '<br>'.join(descriptions)
|
return '<br>'.join(descriptions)
|
||||||
display_description.short_description = _("Description")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Subtotal")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_subtotal(self, line):
|
def display_subtotal(self, line):
|
||||||
subtotals = [' ' + str(line.subtotal)]
|
subtotals = [' ' + str(line.subtotal)]
|
||||||
for subline in line.sublines.all():
|
for subline in line.sublines.all():
|
||||||
subtotals.append(str(subline.total))
|
subtotals.append(str(subline.total))
|
||||||
return '<br>'.join(subtotals)
|
return '<br>'.join(subtotals)
|
||||||
display_subtotal.short_description = _("Subtotal")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Total")
|
||||||
|
)
|
||||||
def display_total(self, line):
|
def display_total(self, line):
|
||||||
if line.pk:
|
if line.pk:
|
||||||
return line.compute_total()
|
return line.compute_total()
|
||||||
display_total.short_description = _("Total")
|
|
||||||
|
|
||||||
def has_add_permission(self, request, obj):
|
def has_add_permission(self, request, obj):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(BillLine)
|
||||||
class BillLineAdmin(admin.ModelAdmin):
|
class BillLineAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'description', 'bill_link', 'display_is_open', 'account_link', 'rate', 'quantity',
|
'description', 'bill_link', 'display_is_open', 'account_link', 'rate', 'quantity',
|
||||||
|
@ -164,21 +173,27 @@ class BillLineAdmin(admin.ModelAdmin):
|
||||||
order_link = admin_link('order')
|
order_link = admin_link('order')
|
||||||
amended_line_link = admin_link('amended_line')
|
amended_line_link = admin_link('amended_line')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Is open"),
|
||||||
|
boolean=True,
|
||||||
|
)
|
||||||
def display_is_open(self, instance):
|
def display_is_open(self, instance):
|
||||||
return instance.bill.is_open
|
return instance.bill.is_open
|
||||||
display_is_open.short_description = _("Is open")
|
|
||||||
display_is_open.boolean = True
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Sublines"),
|
||||||
|
ordering='subline_total',
|
||||||
|
)
|
||||||
def display_sublinetotal(self, instance):
|
def display_sublinetotal(self, instance):
|
||||||
total = instance.subline_total
|
total = instance.subline_total
|
||||||
return total if total is not None else '---'
|
return total if total is not None else '---'
|
||||||
display_sublinetotal.short_description = _("Sublines")
|
|
||||||
display_sublinetotal.admin_order_field = 'subline_total'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Total"),
|
||||||
|
ordering='computed_total',
|
||||||
|
)
|
||||||
def display_total(self, instance):
|
def display_total(self, instance):
|
||||||
return round(instance.computed_total or 0, 2)
|
return round(instance.computed_total or 0, 2)
|
||||||
display_total.short_description = _("Total")
|
|
||||||
display_total.admin_order_field = 'computed_total'
|
|
||||||
|
|
||||||
def get_readonly_fields(self, request, obj=None):
|
def get_readonly_fields(self, request, obj=None):
|
||||||
fields = super().get_readonly_fields(request, obj)
|
fields = super().get_readonly_fields(request, obj)
|
||||||
|
@ -242,6 +257,10 @@ class BillLineManagerAdmin(BillLineAdmin):
|
||||||
|
|
||||||
|
|
||||||
class BillAdminMixin(AccountAdminMixin):
|
class BillAdminMixin(AccountAdminMixin):
|
||||||
|
@admin.display(
|
||||||
|
description=_("total"),
|
||||||
|
ordering='approx_total',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_total_with_subtotals(self, bill):
|
def display_total_with_subtotals(self, bill):
|
||||||
if bill.pk:
|
if bill.pk:
|
||||||
|
@ -252,9 +271,10 @@ class BillAdminMixin(AccountAdminMixin):
|
||||||
subtotals.append(_("Taxes %s%% VAT %s &%s;") % (tax, subtotal[1], currency))
|
subtotals.append(_("Taxes %s%% VAT %s &%s;") % (tax, subtotal[1], currency))
|
||||||
subtotals = '\n'.join(subtotals)
|
subtotals = '\n'.join(subtotals)
|
||||||
return '<span title="%s">%s &%s;</span>' % (subtotals, bill.compute_total(), currency)
|
return '<span title="%s">%s &%s;</span>' % (subtotals, bill.compute_total(), currency)
|
||||||
display_total_with_subtotals.short_description = _("total")
|
|
||||||
display_total_with_subtotals.admin_order_field = 'approx_total'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Payment")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_payment_state(self, bill):
|
def display_payment_state(self, bill):
|
||||||
if bill.pk:
|
if bill.pk:
|
||||||
|
@ -277,7 +297,6 @@ class BillAdminMixin(AccountAdminMixin):
|
||||||
color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey')
|
color = PAYMENT_STATE_COLORS.get(bill.payment_state, 'grey')
|
||||||
return '<a href="{url}" style="color:{color}" title="{title}">{name}</a>'.format(
|
return '<a href="{url}" style="color:{color}" title="{title}">{name}</a>'.format(
|
||||||
url=url, color=color, name=state, title=title)
|
url=url, color=color, name=state, title=title)
|
||||||
display_payment_state.short_description = _("Payment")
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
qs = super().get_queryset(request)
|
||||||
|
@ -311,6 +330,7 @@ class AmendInline(BillAdminMixin, admin.TabularInline):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(AbonoInvoice, AmendmentFee, AmendmentInvoice, Bill, Fee, Invoice, ProForma)
|
||||||
class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'number', 'type_link', 'account_link', 'closed_on_display', 'updated_on_display',
|
'number', 'type_link', 'account_link', 'closed_on_display', 'updated_on_display',
|
||||||
|
@ -369,23 +389,29 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
||||||
# amend_links.short_description = _("Amends")
|
# amend_links.short_description = _("Amends")
|
||||||
# amend_links.allow_tags = True
|
# amend_links.allow_tags = True
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("lines"),
|
||||||
|
ordering='lines__count',
|
||||||
|
)
|
||||||
def num_lines(self, bill):
|
def num_lines(self, bill):
|
||||||
return bill.lines__count
|
return bill.lines__count
|
||||||
num_lines.admin_order_field = 'lines__count'
|
|
||||||
num_lines.short_description = _("lines")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("total"),
|
||||||
|
ordering='approx_total',
|
||||||
|
)
|
||||||
def display_total(self, bill):
|
def display_total(self, bill):
|
||||||
currency = settings.BILLS_CURRENCY.lower()
|
currency = settings.BILLS_CURRENCY.lower()
|
||||||
return format_html('{} &{};', bill.compute_total(), currency)
|
return format_html('{} &{};', bill.compute_total(), currency)
|
||||||
display_total.short_description = _("total")
|
|
||||||
display_total.admin_order_field = 'approx_total'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("type"),
|
||||||
|
ordering='type',
|
||||||
|
)
|
||||||
def type_link(self, bill):
|
def type_link(self, bill):
|
||||||
bill_type = bill.type.lower()
|
bill_type = bill.type.lower()
|
||||||
url = reverse('admin:bills_%s_changelist' % bill_type)
|
url = reverse('admin:bills_%s_changelist' % bill_type)
|
||||||
return format_html('<a href="{}">{}</a>', url, bill.get_type_display())
|
return format_html('<a href="{}">{}</a>', url, bill.get_type_display())
|
||||||
type_link.short_description = _("type")
|
|
||||||
type_link.admin_order_field = 'type'
|
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
""" Hook bill lines management URLs on bill admin """
|
""" Hook bill lines management URLs on bill admin """
|
||||||
|
@ -456,14 +482,6 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
|
||||||
return super().change_view(request, object_id, **kwargs)
|
return super().change_view(request, object_id, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Bill, BillAdmin)
|
|
||||||
admin.site.register(Invoice, BillAdmin)
|
|
||||||
admin.site.register(AmendmentInvoice, BillAdmin)
|
|
||||||
admin.site.register(AbonoInvoice, BillAdmin)
|
|
||||||
admin.site.register(Fee, BillAdmin)
|
|
||||||
admin.site.register(AmendmentFee, BillAdmin)
|
|
||||||
admin.site.register(ProForma, BillAdmin)
|
|
||||||
admin.site.register(BillLine, BillLineAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
class BillContactInline(admin.StackedInline):
|
class BillContactInline(admin.StackedInline):
|
||||||
|
@ -481,10 +499,12 @@ class BillContactInline(admin.StackedInline):
|
||||||
return super().formfield_for_dbfield(db_field, **kwargs)
|
return super().formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
boolean=True,
|
||||||
|
ordering='billcontact',
|
||||||
|
)
|
||||||
def has_bill_contact(account):
|
def has_bill_contact(account):
|
||||||
return hasattr(account, 'billcontact')
|
return hasattr(account, 'billcontact')
|
||||||
has_bill_contact.boolean = True
|
|
||||||
has_bill_contact.admin_order_field = 'billcontact'
|
|
||||||
|
|
||||||
|
|
||||||
insertattr(AccountAdmin, 'inlines', BillContactInline)
|
insertattr(AccountAdmin, 'inlines', BillContactInline)
|
||||||
|
|
|
@ -18,7 +18,7 @@ class BillViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'])
|
||||||
def document(self, request, pk):
|
def document(self, request, pk):
|
||||||
bill = self.get_object()
|
bill = self.get_object()
|
||||||
content_type = request.META.get('HTTP_ACCEPT')
|
content_type = request.headers.get('accept')
|
||||||
if content_type == 'application/pdf':
|
if content_type == 'application/pdf':
|
||||||
pdf = html_to_pdf(bill.html or bill.render())
|
pdf = html_to_pdf(bill.html or bill.render())
|
||||||
return HttpResponse(pdf, content_type='application/pdf')
|
return HttpResponse(pdf, content_type='application/pdf')
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.contacts.apps.ContactsConfig'
|
|
|
@ -13,6 +13,7 @@ from .filters import EmailUsageListFilter
|
||||||
from .models import Contact
|
from .models import Contact
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Contact)
|
||||||
class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'dispaly_name', 'email', 'phone', 'phone2', 'country', 'account_link'
|
'dispaly_name', 'email', 'phone', 'phone2', 'country', 'account_link'
|
||||||
|
@ -62,10 +63,12 @@ class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
actions = (SendEmail(), list_accounts)
|
actions = (SendEmail(), list_accounts)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Name"),
|
||||||
|
ordering='short_name',
|
||||||
|
)
|
||||||
def dispaly_name(self, contact):
|
def dispaly_name(self, contact):
|
||||||
return str(contact)
|
return str(contact)
|
||||||
dispaly_name.short_description = _("Name")
|
|
||||||
dispaly_name.admin_order_field = 'short_name'
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -76,7 +79,6 @@ class ContactAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
return super(ContactAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(ContactAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Contact, ContactAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
class ContactInline(admin.StackedInline):
|
class ContactInline(admin.StackedInline):
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.databases.apps.DatabasesConfig'
|
|
|
@ -14,11 +14,14 @@ from .filters import HasUserListFilter, HasDatabaseListFilter
|
||||||
from .forms import DatabaseCreationForm, DatabaseUserChangeForm, DatabaseUserCreationForm, DatabaseForm
|
from .forms import DatabaseCreationForm, DatabaseUserChangeForm, DatabaseUserCreationForm, DatabaseForm
|
||||||
from .models import Database, DatabaseUser
|
from .models import Database, DatabaseUser
|
||||||
|
|
||||||
|
@admin.action(
|
||||||
|
description="Re-save selected objects"
|
||||||
|
)
|
||||||
def save_selected(modeladmin, request, queryset):
|
def save_selected(modeladmin, request, queryset):
|
||||||
for selected in queryset:
|
for selected in queryset:
|
||||||
selected.save()
|
selected.save()
|
||||||
save_selected.short_description = "Re-save selected objects"
|
|
||||||
|
|
||||||
|
@admin.register(Database)
|
||||||
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'target_server', 'display_users', 'account_link')
|
list_display = ('name', 'type', 'target_server', 'display_users', 'account_link')
|
||||||
list_filter = ('type', HasUserListFilter)
|
list_filter = ('type', HasUserListFilter)
|
||||||
|
@ -51,6 +54,10 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
filter_horizontal = ['users']
|
filter_horizontal = ['users']
|
||||||
actions = (list_accounts, save_selected)
|
actions = (list_accounts, save_selected)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Users"),
|
||||||
|
ordering='users__username',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_users(self, db):
|
def display_users(self, db):
|
||||||
links = []
|
links = []
|
||||||
|
@ -58,8 +65,6 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
link = format_html('<a href="{}">{}</a>', change_url(user), user.username)
|
link = format_html('<a href="{}">{}</a>', change_url(user), user.username)
|
||||||
links.append(link)
|
links.append(link)
|
||||||
return '<br>'.join(links)
|
return '<br>'.join(links)
|
||||||
display_users.short_description = _("Users")
|
|
||||||
display_users.admin_order_field = 'users__username'
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
super(DatabaseAdmin, self).save_model(request, obj, form, change)
|
super(DatabaseAdmin, self).save_model(request, obj, form, change)
|
||||||
|
@ -77,6 +82,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
obj.users.add(user)
|
obj.users.add(user)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(DatabaseUser)
|
||||||
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'target_server', 'type', 'display_databases', 'account_link')
|
list_display = ('username', 'target_server', 'type', 'display_databases', 'account_link')
|
||||||
list_filter = ('type', HasDatabaseListFilter)
|
list_filter = ('type', HasDatabaseListFilter)
|
||||||
|
@ -101,6 +107,10 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
list_prefetch_related = ('databases',)
|
list_prefetch_related = ('databases',)
|
||||||
actions = (list_accounts, save_selected)
|
actions = (list_accounts, save_selected)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Databases"),
|
||||||
|
ordering='databases__name',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_databases(self, user):
|
def display_databases(self, user):
|
||||||
links = []
|
links = []
|
||||||
|
@ -108,8 +118,6 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
link = format_html('<a href="{}">{}</a>', change_url(db), db.name)
|
link = format_html('<a href="{}">{}</a>', change_url(db), db.name)
|
||||||
links.append(link)
|
links.append(link)
|
||||||
return '<br>'.join(links)
|
return '<br>'.join(links)
|
||||||
display_databases.short_description = _("Databases")
|
|
||||||
display_databases.admin_order_field = 'databases__name'
|
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
useradmin = UserAdmin(DatabaseUser, self.admin_site)
|
useradmin = UserAdmin(DatabaseUser, self.admin_site)
|
||||||
|
@ -125,5 +133,3 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
super(DatabaseUserAdmin, self).save_model(request, obj, form, change)
|
super(DatabaseUserAdmin, self).save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Database, DatabaseAdmin)
|
|
||||||
admin.site.register(DatabaseUser, DatabaseUserAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.domains.apps.DomainsConfig'
|
|
|
@ -39,9 +39,11 @@ class DomainInline(admin.TabularInline):
|
||||||
domain_link.short_description = _("Name")
|
domain_link.short_description = _("Name")
|
||||||
account_link = admin_link('account')
|
account_link = admin_link('account')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Declared records")
|
||||||
|
)
|
||||||
def display_records(self, domain):
|
def display_records(self, domain):
|
||||||
return ', '.join([record.type for record in domain.records.all()])
|
return ', '.join([record.type for record in domain.records.all()])
|
||||||
display_records.short_description = _("Declared records")
|
|
||||||
|
|
||||||
def has_add_permission(self, *args, **kwargs):
|
def has_add_permission(self, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
@ -52,6 +54,7 @@ class DomainInline(admin.TabularInline):
|
||||||
return qs.select_related('account').prefetch_related('records')
|
return qs.select_related('account').prefetch_related('records')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Domain)
|
||||||
class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'structured_name', 'display_is_top', 'display_websites', 'display_addresses', 'account_link'
|
'structured_name', 'display_is_top', 'display_websites', 'display_addresses', 'account_link'
|
||||||
|
@ -71,19 +74,27 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
top_link = admin_link('top')
|
top_link = admin_link('top')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("name"),
|
||||||
|
ordering='structured_name',
|
||||||
|
)
|
||||||
def structured_name(self, domain):
|
def structured_name(self, domain):
|
||||||
if domain.is_top:
|
if domain.is_top:
|
||||||
return domain.name
|
return domain.name
|
||||||
return mark_safe(' '*4 + domain.name)
|
return mark_safe(' '*4 + domain.name)
|
||||||
structured_name.short_description = _("name")
|
|
||||||
structured_name.admin_order_field = 'structured_name'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Is top"),
|
||||||
|
boolean=True,
|
||||||
|
ordering='top',
|
||||||
|
)
|
||||||
def display_is_top(self, domain):
|
def display_is_top(self, domain):
|
||||||
return domain.is_top
|
return domain.is_top
|
||||||
display_is_top.short_description = _("Is top")
|
|
||||||
display_is_top.boolean = True
|
|
||||||
display_is_top.admin_order_field = 'top'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Websites"),
|
||||||
|
ordering='websites__name',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_websites(self, domain):
|
def display_websites(self, domain):
|
||||||
if apps.isinstalled('orchestra.contrib.websites'):
|
if apps.isinstalled('orchestra.contrib.websites'):
|
||||||
|
@ -106,9 +117,11 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
)
|
)
|
||||||
return _("No website %s") % (add_link)
|
return _("No website %s") % (add_link)
|
||||||
return '---'
|
return '---'
|
||||||
display_websites.admin_order_field = 'websites__name'
|
|
||||||
display_websites.short_description = _("Websites")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Addresses"),
|
||||||
|
ordering='addresses__count',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_addresses(self, domain):
|
def display_addresses(self, domain):
|
||||||
if apps.isinstalled('orchestra.contrib.mailboxes'):
|
if apps.isinstalled('orchestra.contrib.mailboxes'):
|
||||||
|
@ -126,9 +139,10 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
return '<a href="%s" title="%s">%s</a> %s' % (url, title, len(addresses), add_link)
|
return '<a href="%s" title="%s">%s</a> %s' % (url, title, len(addresses), add_link)
|
||||||
return _("No address %s") % (add_link)
|
return _("No address %s") % (add_link)
|
||||||
return '---'
|
return '---'
|
||||||
display_addresses.short_description = _("Addresses")
|
|
||||||
display_addresses.admin_order_field = 'addresses__count'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Implicit records")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def implicit_records(self, domain):
|
def implicit_records(self, domain):
|
||||||
types = set(domain.records.values_list('type', flat=True))
|
types = set(domain.records.values_list('type', flat=True))
|
||||||
|
@ -148,7 +162,6 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
else:
|
else:
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
return '<br>'.join(lines)
|
return '<br>'.join(lines)
|
||||||
implicit_records.short_description = _("Implicit records")
|
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def get_fieldsets(self, request, obj=None):
|
||||||
""" Add SOA fields when domain is top """
|
""" Add SOA fields when domain is top """
|
||||||
|
@ -224,4 +237,3 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
self.save_formset(request, form, formset, change)
|
self.save_formset(request, form, formset, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Domain, DomainAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.history.apps.HistoryConfig'
|
|
|
@ -36,6 +36,10 @@ class LogEntryAdmin(admin.ModelAdmin):
|
||||||
user_link = admin_link('user')
|
user_link = admin_link('user')
|
||||||
display_action_time = admin_date('action_time', short_description=_("Time"))
|
display_action_time = admin_date('action_time', short_description=_("Time"))
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Message"),
|
||||||
|
ordering='action_flag',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_message(self, log):
|
def display_message(self, log):
|
||||||
edit = format_html('<a href="{url}"><img src="{img}"></img></a>', **{
|
edit = format_html('<a href="{url}"><img src="{img}"></img></a>', **{
|
||||||
|
@ -58,18 +62,22 @@ class LogEntryAdmin(admin.ModelAdmin):
|
||||||
'object': log.object_repr,
|
'object': log.object_repr,
|
||||||
'edit': edit,
|
'edit': edit,
|
||||||
}
|
}
|
||||||
display_message.short_description = _("Message")
|
|
||||||
display_message.admin_order_field = 'action_flag'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Action"),
|
||||||
|
ordering='action_flag',
|
||||||
|
)
|
||||||
def display_action(self, log):
|
def display_action(self, log):
|
||||||
if log.is_addition():
|
if log.is_addition():
|
||||||
return _("Added")
|
return _("Added")
|
||||||
elif log.is_change():
|
elif log.is_change():
|
||||||
return _("Changed")
|
return _("Changed")
|
||||||
return _("Deleted")
|
return _("Deleted")
|
||||||
display_action.short_description = _("Action")
|
|
||||||
display_action.admin_order_field = 'action_flag'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Content object"),
|
||||||
|
ordering='object_repr',
|
||||||
|
)
|
||||||
def content_object_link(self, log):
|
def content_object_link(self, log):
|
||||||
ct = log.content_type
|
ct = log.content_type
|
||||||
view = 'admin:%s_%s_change' % (ct.app_label, ct.model)
|
view = 'admin:%s_%s_change' % (ct.app_label, ct.model)
|
||||||
|
@ -78,8 +86,6 @@ class LogEntryAdmin(admin.ModelAdmin):
|
||||||
except NoReverseMatch:
|
except NoReverseMatch:
|
||||||
return log.object_repr
|
return log.object_repr
|
||||||
return format_html('<a href="{}">{}</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'
|
|
||||||
|
|
||||||
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
||||||
""" Add rel_opts and object to context """
|
""" Add rel_opts and object to context """
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.issues.apps.IssuesConfig'
|
|
|
@ -51,6 +51,9 @@ class MessageReadOnlyInline(admin.TabularInline):
|
||||||
'all': ('orchestra/css/hide-inline-id.css',)
|
'all': ('orchestra/css/hide-inline-id.css',)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Content")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def content_html(self, msg):
|
def content_html(self, msg):
|
||||||
context = {
|
context = {
|
||||||
|
@ -66,7 +69,6 @@ class MessageReadOnlyInline(admin.TabularInline):
|
||||||
content = '<div style="padding-left:20px;">%s</div>' % content
|
content = '<div style="padding-left:20px;">%s</div>' % content
|
||||||
|
|
||||||
return header + content
|
return header + content
|
||||||
content_html.short_description = _("Content")
|
|
||||||
|
|
||||||
def has_add_permission(self, request, obj):
|
def has_add_permission(self, request, obj):
|
||||||
return False
|
return False
|
||||||
|
@ -114,12 +116,15 @@ class TicketInline(admin.TabularInline):
|
||||||
colored_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
colored_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||||
colored_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
colored_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description='#'
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def ticket_id(self, instance):
|
def ticket_id(self, instance):
|
||||||
return '<b>%s</b>' % admin_link()(instance)
|
return '<b>%s</b>' % admin_link()(instance)
|
||||||
ticket_id.short_description = '#'
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Ticket)
|
||||||
class TicketAdmin(ExtendedModelAdmin):
|
class TicketAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'unbold_id', 'bold_subject', 'display_creator', 'display_owner',
|
'unbold_id', 'bold_subject', 'display_creator', 'display_owner',
|
||||||
|
@ -195,6 +200,9 @@ class TicketAdmin(ExtendedModelAdmin):
|
||||||
display_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
display_state = admin_colored('state', colors=STATE_COLORS, bold=False)
|
||||||
display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description='Summary'
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_summary(self, ticket):
|
def display_summary(self, ticket):
|
||||||
context = {
|
context = {
|
||||||
|
@ -210,23 +218,26 @@ class TicketAdmin(ExtendedModelAdmin):
|
||||||
})
|
})
|
||||||
context['updated'] = '. Updated by %(updater)s about %(updated)s' % context
|
context['updated'] = '. Updated by %(updater)s about %(updated)s' % context
|
||||||
return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
|
return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
|
||||||
display_summary.short_description = 'Summary'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description="#",
|
||||||
|
ordering='id',
|
||||||
|
)
|
||||||
def unbold_id(self, ticket):
|
def unbold_id(self, ticket):
|
||||||
""" Unbold id if ticket is read """
|
""" Unbold id if ticket is read """
|
||||||
if ticket.is_read_by(self.user):
|
if ticket.is_read_by(self.user):
|
||||||
return format_html('<span style="font-weight:normal;font-size:11px;">{}</span>', ticket.pk)
|
return format_html('<span style="font-weight:normal;font-size:11px;">{}</span>', ticket.pk)
|
||||||
return ticket.pk
|
return ticket.pk
|
||||||
unbold_id.short_description = "#"
|
|
||||||
unbold_id.admin_order_field = 'id'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Subject"),
|
||||||
|
ordering='subject',
|
||||||
|
)
|
||||||
def bold_subject(self, ticket):
|
def bold_subject(self, ticket):
|
||||||
""" Bold subject when tickets are unread for request.user """
|
""" Bold subject when tickets are unread for request.user """
|
||||||
if ticket.is_read_by(self.user):
|
if ticket.is_read_by(self.user):
|
||||||
return ticket.subject
|
return ticket.subject
|
||||||
return format_html("<strong class='unread'>{}</strong>", ticket.subject)
|
return format_html("<strong class='unread'>{}</strong>", ticket.subject)
|
||||||
bold_subject.short_description = _("Subject")
|
|
||||||
bold_subject.admin_order_field = 'subject'
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -283,6 +294,7 @@ class TicketAdmin(ExtendedModelAdmin):
|
||||||
return HttpResponse(data_formated)
|
return HttpResponse(data_formated)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Queue)
|
||||||
class QueueAdmin(admin.ModelAdmin):
|
class QueueAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'default', 'num_tickets')
|
list_display = ('name', 'default', 'num_tickets')
|
||||||
actions = (set_default_queue,)
|
actions = (set_default_queue,)
|
||||||
|
@ -294,13 +306,15 @@ class QueueAdmin(admin.ModelAdmin):
|
||||||
'all': ('orchestra/css/hide-inline-id.css',)
|
'all': ('orchestra/css/hide-inline-id.css',)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Tickets"),
|
||||||
|
ordering='tickets__count',
|
||||||
|
)
|
||||||
def num_tickets(self, queue):
|
def num_tickets(self, queue):
|
||||||
num = queue.tickets__count
|
num = queue.tickets__count
|
||||||
url = reverse('admin:issues_ticket_changelist')
|
url = reverse('admin:issues_ticket_changelist')
|
||||||
url += '?queue=%i' % queue.pk
|
url += '?queue=%i' % queue.pk
|
||||||
return format_html('<a href="{}">{}</a>', url, num)
|
return format_html('<a href="{}">{}</a>', url, num)
|
||||||
num_tickets.short_description = _("Tickets")
|
|
||||||
num_tickets.admin_order_field = 'tickets__count'
|
|
||||||
|
|
||||||
def get_list_display(self, request):
|
def get_list_display(self, request):
|
||||||
""" show notifications """
|
""" show notifications """
|
||||||
|
@ -319,5 +333,3 @@ class QueueAdmin(admin.ModelAdmin):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Ticket, TicketAdmin)
|
|
||||||
admin.site.register(Queue, QueueAdmin)
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ from .helpers import is_valid_domain, read_live_lineages, configure_cert
|
||||||
from .forms import LetsEncryptForm
|
from .forms import LetsEncryptForm
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(
|
||||||
|
description="Let's encrypt!"
|
||||||
|
)
|
||||||
def letsencrypt(modeladmin, request, queryset):
|
def letsencrypt(modeladmin, request, queryset):
|
||||||
wildcards = set()
|
wildcards = set()
|
||||||
domains = set()
|
domains = set()
|
||||||
|
@ -112,4 +115,3 @@ def letsencrypt(modeladmin, request, queryset):
|
||||||
'form': form,
|
'form': form,
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, 'admin/orchestra/generic_confirmation.html', context)
|
return TemplateResponse(request, 'admin/orchestra/generic_confirmation.html', context)
|
||||||
letsencrypt.short_description = "Let's encrypt!"
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.lists.apps.ListsConfig'
|
|
|
@ -16,6 +16,7 @@ from .filters import HasCustomAddressListFilter
|
||||||
from .models import List
|
from .models import List
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(List)
|
||||||
class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'name', 'address_name', 'address_domain_link', 'account_link', 'display_active'
|
'name', 'address_name', 'address_domain_link', 'account_link', 'display_active'
|
||||||
|
@ -56,4 +57,3 @@ class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
address_domain_link = admin_link('address_domain', order='address_domain__name')
|
address_domain_link = admin_link('address_domain', order='address_domain__name')
|
||||||
|
|
||||||
admin.site.register(List, ListAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.mailboxes.apps.MailboxesConfig'
|
|
|
@ -83,6 +83,9 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
if settings.MAILBOXES_LOCAL_DOMAIN:
|
if settings.MAILBOXES_LOCAL_DOMAIN:
|
||||||
type(self).actions = self.actions + (SendMailboxEmail(),)
|
type(self).actions = self.actions + (SendMailboxEmail(),)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Addresses")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_addresses(self, mailbox):
|
def display_addresses(self, mailbox):
|
||||||
# Get from forwards
|
# Get from forwards
|
||||||
|
@ -111,21 +114,24 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
url = change_url(addr)
|
url = change_url(addr)
|
||||||
addresses.append(format_html('<a href="{}">{}</a>', url, addr.email))
|
addresses.append(format_html('<a href="{}">{}</a>', url, addr.email))
|
||||||
return '<br>'.join(addresses+forwards)
|
return '<br>'.join(addresses+forwards)
|
||||||
display_addresses.short_description = _("Addresses")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Forward from")
|
||||||
|
)
|
||||||
def display_forwards(self, mailbox):
|
def display_forwards(self, mailbox):
|
||||||
forwards = mailbox.get_forwards()
|
forwards = mailbox.get_forwards()
|
||||||
return format_html_join(
|
return format_html_join(
|
||||||
'<br>', '<a href="{}">{}</a>',
|
'<br>', '<a href="{}">{}</a>',
|
||||||
[(change_url(addr), addr.email) for addr in forwards]
|
[(change_url(addr), addr.email) for addr in forwards]
|
||||||
)
|
)
|
||||||
display_forwards.short_description = _("Forward from")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Filtering"),
|
||||||
|
ordering='filtering',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_filtering(self, mailbox):
|
def display_filtering(self, mailbox):
|
||||||
return mailbox.get_filtering_display()
|
return mailbox.get_filtering_display()
|
||||||
display_filtering.short_description = _("Filtering")
|
|
||||||
display_filtering.admin_order_field = 'filtering'
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
if db_field.name == 'filtering':
|
if db_field.name == 'filtering':
|
||||||
|
@ -221,6 +227,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
obj.addresses.set(form.cleaned_data['addresses'])
|
obj.addresses.set(form.cleaned_data['addresses'])
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Address)
|
||||||
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'display_email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward',
|
'display_email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward',
|
||||||
|
@ -241,33 +248,45 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
domain_link = admin_link('domain', order='domain__name')
|
domain_link = admin_link('domain', order='domain__name')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Email"),
|
||||||
|
ordering='computed_email',
|
||||||
|
)
|
||||||
def display_email(self, address):
|
def display_email(self, address):
|
||||||
return address.computed_email
|
return address.computed_email
|
||||||
display_email.short_description = _("Email")
|
|
||||||
display_email.admin_order_field = 'computed_email'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Email")
|
||||||
|
)
|
||||||
def email_link(self, address):
|
def email_link(self, address):
|
||||||
link = self.domain_link(address)
|
link = self.domain_link(address)
|
||||||
return format_html("{}@{}", address.name, link)
|
return format_html("{}@{}", address.name, link)
|
||||||
email_link.short_description = _("Email")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Mailboxes"),
|
||||||
|
ordering='mailboxes__count',
|
||||||
|
)
|
||||||
def display_mailboxes(self, address):
|
def display_mailboxes(self, address):
|
||||||
boxes = address.mailboxes.all()
|
boxes = address.mailboxes.all()
|
||||||
return format_html_join(
|
return format_html_join(
|
||||||
mark_safe('<br>'), '<a href="{}">{}</a>',
|
mark_safe('<br>'), '<a href="{}">{}</a>',
|
||||||
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
||||||
)
|
)
|
||||||
display_mailboxes.short_description = _("Mailboxes")
|
|
||||||
display_mailboxes.admin_order_field = 'mailboxes__count'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Mailboxes links")
|
||||||
|
)
|
||||||
def display_all_mailboxes(self, address):
|
def display_all_mailboxes(self, address):
|
||||||
boxes = address.get_mailboxes()
|
boxes = address.get_mailboxes()
|
||||||
return format_html_join(
|
return format_html_join(
|
||||||
mark_safe('<br>'), '<a href="{}">{}</a>',
|
mark_safe('<br>'), '<a href="{}">{}</a>',
|
||||||
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
[(change_url(mailbox), mailbox.name) for mailbox in boxes]
|
||||||
)
|
)
|
||||||
display_all_mailboxes.short_description = _("Mailboxes links")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Forward"),
|
||||||
|
ordering='forward',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_forward(self, address):
|
def display_forward(self, address):
|
||||||
forward_mailboxes = {m.name: m for m in address.get_forward_mailboxes()}
|
forward_mailboxes = {m.name: m for m in address.get_forward_mailboxes()}
|
||||||
|
@ -279,8 +298,6 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
else:
|
else:
|
||||||
values.append(forward)
|
values.append(forward)
|
||||||
return '<br>'.join(values)
|
return '<br>'.join(values)
|
||||||
display_forward.short_description = _("Forward")
|
|
||||||
display_forward.admin_order_field = 'forward'
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
if db_field.name == 'forward':
|
if db_field.name == 'forward':
|
||||||
|
@ -326,4 +343,3 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Mailbox, MailboxAdmin)
|
admin.site.register(Mailbox, MailboxAdmin)
|
||||||
admin.site.register(Address, AddressAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.mailer.apps.MailerConfig'
|
|
|
@ -29,6 +29,7 @@ COLORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Message)
|
||||||
class MessageAdmin(ExtendedModelAdmin):
|
class MessageAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'display_subject', 'colored_state', 'priority', 'to_address', 'from_address',
|
'display_subject', 'colored_state', 'priority', 'to_address', 'from_address',
|
||||||
|
@ -59,14 +60,20 @@ class MessageAdmin(ExtendedModelAdmin):
|
||||||
created_at_delta = admin_date('created_at')
|
created_at_delta = admin_date('created_at')
|
||||||
last_try_delta = admin_date('last_try')
|
last_try_delta = admin_date('last_try')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Subject"),
|
||||||
|
ordering='subject',
|
||||||
|
)
|
||||||
def display_subject(self, instance):
|
def display_subject(self, instance):
|
||||||
subject = instance.subject
|
subject = instance.subject
|
||||||
if len(subject) > 64:
|
if len(subject) > 64:
|
||||||
return mark_safe(subject[:64] + '…')
|
return mark_safe(subject[:64] + '…')
|
||||||
return subject
|
return subject
|
||||||
display_subject.short_description = _("Subject")
|
|
||||||
display_subject.admin_order_field = 'subject'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Retries"),
|
||||||
|
ordering='retries',
|
||||||
|
)
|
||||||
def display_retries(self, instance):
|
def display_retries(self, instance):
|
||||||
num_logs = instance.logs__count
|
num_logs = instance.logs__count
|
||||||
if num_logs == 1:
|
if num_logs == 1:
|
||||||
|
@ -76,9 +83,10 @@ class MessageAdmin(ExtendedModelAdmin):
|
||||||
url = reverse('admin:mailer_smtplog_changelist')
|
url = reverse('admin:mailer_smtplog_changelist')
|
||||||
url += '?&message=%i' % instance.pk
|
url += '?&message=%i' % instance.pk
|
||||||
return format_html('<a href="{}" onclick="return showAddAnotherPopup(this);">{}</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'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Content")
|
||||||
|
)
|
||||||
def display_content(self, instance):
|
def display_content(self, instance):
|
||||||
part = email.message_from_string(instance.content)
|
part = email.message_from_string(instance.content)
|
||||||
payload = part.get_payload()
|
payload = part.get_payload()
|
||||||
|
@ -100,19 +108,24 @@ class MessageAdmin(ExtendedModelAdmin):
|
||||||
if part.get_content_type() == 'text/plain':
|
if part.get_content_type() == 'text/plain':
|
||||||
payload = payload.replace('\n', '<br>').replace(' ', ' ')
|
payload = payload.replace('\n', '<br>').replace(' ', ' ')
|
||||||
return mark_safe(payload)
|
return mark_safe(payload)
|
||||||
display_content.short_description = _("Content")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Subject")
|
||||||
|
)
|
||||||
def display_full_subject(self, instance):
|
def display_full_subject(self, instance):
|
||||||
return instance.subject
|
return instance.subject
|
||||||
display_full_subject.short_description = _("Subject")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("From")
|
||||||
|
)
|
||||||
def display_from(self, instance):
|
def display_from(self, instance):
|
||||||
return instance.from_address
|
return instance.from_address
|
||||||
display_from.short_description = _("From")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("To")
|
||||||
|
)
|
||||||
def display_to(self, instance):
|
def display_to(self, instance):
|
||||||
return instance.to_address
|
return instance.to_address
|
||||||
display_to.short_description = _("To")
|
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
from django.urls import re_path as url
|
from django.urls import re_path as url
|
||||||
|
@ -140,6 +153,7 @@ class MessageAdmin(ExtendedModelAdmin):
|
||||||
return super().formfield_for_dbfield(db_field, **kwargs)
|
return super().formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SMTPLog)
|
||||||
class SMTPLogAdmin(admin.ModelAdmin):
|
class SMTPLogAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'message_link', 'colored_result', 'date_delta', 'log_message'
|
'id', 'message_link', 'colored_result', 'date_delta', 'log_message'
|
||||||
|
@ -153,5 +167,3 @@ class SMTPLogAdmin(admin.ModelAdmin):
|
||||||
date_delta = admin_date('date')
|
date_delta = admin_date('date')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Message, MessageAdmin)
|
|
||||||
admin.site.register(SMTPLog, SMTPLogAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.miscellaneous.apps.MiscellaneousConfig'
|
|
|
@ -25,6 +25,7 @@ class MiscServicePlugin(PluginModelAdapter):
|
||||||
plugin_field = 'service'
|
plugin_field = 'service'
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(MiscService)
|
||||||
class MiscServiceAdmin(ExtendedModelAdmin):
|
class MiscServiceAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'display_name', 'display_verbose_name', 'num_instances', 'has_identifier', 'has_amount', 'is_active'
|
'display_name', 'display_verbose_name', 'num_instances', 'has_identifier', 'has_amount', 'is_active'
|
||||||
|
@ -38,24 +39,30 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
actions = (disable, enable)
|
actions = (disable, enable)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("name"),
|
||||||
|
ordering='name',
|
||||||
|
)
|
||||||
def display_name(self, misc):
|
def display_name(self, misc):
|
||||||
return format_html('<span title="{}">{}</span>', misc.description, misc.name)
|
return format_html('<span title="{}">{}</span>', misc.description, misc.name)
|
||||||
display_name.short_description = _("name")
|
|
||||||
display_name.admin_order_field = 'name'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("verbose name"),
|
||||||
|
ordering='verbose_name',
|
||||||
|
)
|
||||||
def display_verbose_name(self, misc):
|
def display_verbose_name(self, misc):
|
||||||
return format_html('<span title="{}">{}</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.admin_order_field = 'verbose_name'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Instances"),
|
||||||
|
ordering='instances__count',
|
||||||
|
)
|
||||||
def num_instances(self, misc):
|
def num_instances(self, misc):
|
||||||
""" return num slivers as a link to slivers changelist view """
|
""" return num slivers as a link to slivers changelist view """
|
||||||
num = misc.instances__count
|
num = misc.instances__count
|
||||||
url = reverse('admin:miscellaneous_miscellaneous_changelist')
|
url = reverse('admin:miscellaneous_miscellaneous_changelist')
|
||||||
url += '?service__name={}'.format(misc.name)
|
url += '?service__name={}'.format(misc.name)
|
||||||
return mark_safe('<a href="{0}">{1}</a>'.format(url, num))
|
return mark_safe('<a href="{0}">{1}</a>'.format(url, num))
|
||||||
num_instances.short_description = _("Instances")
|
|
||||||
num_instances.admin_order_field = 'instances__count'
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(MiscServiceAdmin, self).get_queryset(request)
|
qs = super(MiscServiceAdmin, self).get_queryset(request)
|
||||||
|
@ -68,6 +75,7 @@ class MiscServiceAdmin(ExtendedModelAdmin):
|
||||||
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(MiscServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Miscellaneous)
|
||||||
class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
|
'__str__', 'service_link', 'amount', 'account_link', 'dispaly_active'
|
||||||
|
@ -85,11 +93,13 @@ class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedMode
|
||||||
|
|
||||||
service_link = admin_link('service')
|
service_link = admin_link('service')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Active"),
|
||||||
|
boolean=True,
|
||||||
|
ordering='is_active',
|
||||||
|
)
|
||||||
def dispaly_active(self, instance):
|
def dispaly_active(self, instance):
|
||||||
return instance.active
|
return instance.active
|
||||||
dispaly_active.short_description = _("Active")
|
|
||||||
dispaly_active.boolean = True
|
|
||||||
dispaly_active.admin_order_field = 'is_active'
|
|
||||||
|
|
||||||
def get_service(self, obj):
|
def get_service(self, obj):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
|
@ -146,5 +156,3 @@ class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedMode
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(MiscService, MiscServiceAdmin)
|
|
||||||
admin.site.register(Miscellaneous, MiscellaneousAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.musician.apps.MusicianConfig'
|
|
|
@ -160,25 +160,25 @@ msgstr "Cancel·lar"
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Desar"
|
msgstr "Desar"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:15
|
#: templates/musician/address_list.html:15
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Correu electrònic"
|
msgstr "Correu electrònic"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:16
|
#: templates/musician/address_list.html:16
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domini"
|
msgstr "Domini"
|
||||||
|
|
||||||
#. Translators: This message appears on the page title
|
#. Translators: This message appears on the page title
|
||||||
#: templates/musician/addresses.html:17 templates/musician/mail_base.html:22
|
#: templates/musician/address_list.html:17 templates/musician/mail_base.html:22
|
||||||
#: views.py:355
|
#: views.py:355
|
||||||
msgid "Mailboxes"
|
msgid "Mailboxes"
|
||||||
msgstr "Bústies de correu"
|
msgstr "Bústies de correu"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:18
|
#: templates/musician/address_list.html:18
|
||||||
msgid "Forward"
|
msgid "Forward"
|
||||||
msgstr "Redirecció"
|
msgstr "Redirecció"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:38
|
#: templates/musician/address_list.html:38
|
||||||
msgid "New mail address"
|
msgid "New mail address"
|
||||||
msgstr "Nova adreça de correu"
|
msgstr "Nova adreça de correu"
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ msgstr "Obre el gestor de bases de dades"
|
||||||
|
|
||||||
#. Translators: database page when there isn't any database.
|
#. Translators: database page when there isn't any database.
|
||||||
#. Translators: saas page when there isn't any saas.
|
#. Translators: saas page when there isn't any saas.
|
||||||
#: templates/musician/databases.html:58 templates/musician/saas.html:49
|
#: templates/musician/databases.html:58 templates/musician/saas_list.html:49
|
||||||
msgid "Ooops! Looks like there is nothing here!"
|
msgid "Ooops! Looks like there is nothing here!"
|
||||||
msgstr "Mmmh, sembla que aquí no hi ha res!"
|
msgstr "Mmmh, sembla que aquí no hi ha res!"
|
||||||
|
|
||||||
|
@ -370,15 +370,15 @@ msgstr "Consulta aquí la teva configuració DNS."
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr "Valor"
|
msgstr "Valor"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:6 templates/musician/mailinglists.html:6
|
#: templates/musician/mail_base.html:6 templates/musician/mailinglist_list.html:6
|
||||||
msgid "Go to global"
|
msgid "Go to global"
|
||||||
msgstr "Totes les adreces"
|
msgstr "Totes les adreces"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:10 templates/musician/mailinglists.html:9
|
#: templates/musician/mail_base.html:10 templates/musician/mailinglist_list.html:9
|
||||||
msgid "for"
|
msgid "for"
|
||||||
msgstr "per a"
|
msgstr "per a"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:18 templates/musician/mailboxes.html:16
|
#: templates/musician/mail_base.html:18 templates/musician/mailbox_list.html:16
|
||||||
msgid "Addresses"
|
msgid "Addresses"
|
||||||
msgstr "Adreces de correu"
|
msgstr "Adreces de correu"
|
||||||
|
|
||||||
|
@ -415,27 +415,27 @@ msgstr ""
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tancar"
|
msgstr "Tancar"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:14
|
#: templates/musician/mailbox_list.html:14
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:15
|
#: templates/musician/mailbox_list.html:15
|
||||||
msgid "Filtering"
|
msgid "Filtering"
|
||||||
msgstr "Filtrat"
|
msgstr "Filtrat"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:27
|
#: templates/musician/mailbox_list.html:27
|
||||||
msgid "Update password"
|
msgid "Update password"
|
||||||
msgstr "Actualitza la contrasenya"
|
msgstr "Actualitza la contrasenya"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:43
|
#: templates/musician/mailbox_list.html:43
|
||||||
msgid "New mailbox"
|
msgid "New mailbox"
|
||||||
msgstr "Nova bústia de correu"
|
msgstr "Nova bústia de correu"
|
||||||
|
|
||||||
#: templates/musician/mailinglists.html:34
|
#: templates/musician/mailinglist_list.html:34
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actiu"
|
msgstr "Actiu"
|
||||||
|
|
||||||
#: templates/musician/mailinglists.html:36
|
#: templates/musician/mailinglist_list.html:36
|
||||||
msgid "Inactive"
|
msgid "Inactive"
|
||||||
msgstr "Inactiu"
|
msgstr "Inactiu"
|
||||||
|
|
||||||
|
@ -463,19 +463,19 @@ msgstr "mètode de pagament:"
|
||||||
msgid "Check your last bills"
|
msgid "Check your last bills"
|
||||||
msgstr "Consulta les teves darreres factures"
|
msgstr "Consulta les teves darreres factures"
|
||||||
|
|
||||||
#: templates/musician/saas.html:18
|
#: templates/musician/saas_list.html:18
|
||||||
msgid "Installed on"
|
msgid "Installed on"
|
||||||
msgstr "Instal·lat a"
|
msgstr "Instal·lat a"
|
||||||
|
|
||||||
#: templates/musician/saas.html:29
|
#: templates/musician/saas_list.html:29
|
||||||
msgid "Service info"
|
msgid "Service info"
|
||||||
msgstr "Informació del servei"
|
msgstr "Informació del servei"
|
||||||
|
|
||||||
#: templates/musician/saas.html:30
|
#: templates/musician/saas_list.html:30
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "actiu"
|
msgstr "actiu"
|
||||||
|
|
||||||
#: templates/musician/saas.html:37
|
#: templates/musician/saas_list.html:37
|
||||||
msgid "Open service admin panel"
|
msgid "Open service admin panel"
|
||||||
msgstr "Obre el panell d’administració del servei"
|
msgstr "Obre el panell d’administració del servei"
|
||||||
|
|
||||||
|
|
|
@ -162,25 +162,25 @@ msgstr "Cancelar"
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Guardar"
|
msgstr "Guardar"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:15
|
#: templates/musician/address_list.html:15
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Correo electrónico"
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:16
|
#: templates/musician/address_list.html:16
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Dominio"
|
msgstr "Dominio"
|
||||||
|
|
||||||
#. Translators: This message appears on the page title
|
#. Translators: This message appears on the page title
|
||||||
#: templates/musician/addresses.html:17 templates/musician/mail_base.html:22
|
#: templates/musician/address_list.html:17 templates/musician/mail_base.html:22
|
||||||
#: views.py:355
|
#: views.py:355
|
||||||
msgid "Mailboxes"
|
msgid "Mailboxes"
|
||||||
msgstr "Buzones de correo"
|
msgstr "Buzones de correo"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:18
|
#: templates/musician/address_list.html:18
|
||||||
msgid "Forward"
|
msgid "Forward"
|
||||||
msgstr "Redirección"
|
msgstr "Redirección"
|
||||||
|
|
||||||
#: templates/musician/addresses.html:38
|
#: templates/musician/address_list.html:38
|
||||||
msgid "New mail address"
|
msgid "New mail address"
|
||||||
msgstr "Nueva dirección de correo"
|
msgstr "Nueva dirección de correo"
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ msgstr "Abre el gestor de bases de datos"
|
||||||
|
|
||||||
#. Translators: database page when there isn't any database.
|
#. Translators: database page when there isn't any database.
|
||||||
#. Translators: saas page when there isn't any saas.
|
#. Translators: saas page when there isn't any saas.
|
||||||
#: templates/musician/databases.html:58 templates/musician/saas.html:49
|
#: templates/musician/databases.html:58 templates/musician/saas_list.html:49
|
||||||
msgid "Ooops! Looks like there is nothing here!"
|
msgid "Ooops! Looks like there is nothing here!"
|
||||||
msgstr "Mmmh… ¡parece que aquí no hay nada!"
|
msgstr "Mmmh… ¡parece que aquí no hay nada!"
|
||||||
|
|
||||||
|
@ -372,15 +372,15 @@ msgstr "Consulta aquí tu configuración DNS."
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr "Valor"
|
msgstr "Valor"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:6 templates/musician/mailinglists.html:6
|
#: templates/musician/mail_base.html:6 templates/musician/mailinglist_list.html:6
|
||||||
msgid "Go to global"
|
msgid "Go to global"
|
||||||
msgstr "Todas las direcciones"
|
msgstr "Todas las direcciones"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:10 templates/musician/mailinglists.html:9
|
#: templates/musician/mail_base.html:10 templates/musician/mailinglist_list.html:9
|
||||||
msgid "for"
|
msgid "for"
|
||||||
msgstr "para"
|
msgstr "para"
|
||||||
|
|
||||||
#: templates/musician/mail_base.html:18 templates/musician/mailboxes.html:16
|
#: templates/musician/mail_base.html:18 templates/musician/mailbox_list.html:16
|
||||||
msgid "Addresses"
|
msgid "Addresses"
|
||||||
msgstr "Direcciones de correo"
|
msgstr "Direcciones de correo"
|
||||||
|
|
||||||
|
@ -417,27 +417,27 @@ msgstr ""
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Cerrar"
|
msgstr "Cerrar"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:14
|
#: templates/musician/mailbox_list.html:14
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:15
|
#: templates/musician/mailbox_list.html:15
|
||||||
msgid "Filtering"
|
msgid "Filtering"
|
||||||
msgstr "Filtrado"
|
msgstr "Filtrado"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:27
|
#: templates/musician/mailbox_list.html:27
|
||||||
msgid "Update password"
|
msgid "Update password"
|
||||||
msgstr "Actualiza la contraseña"
|
msgstr "Actualiza la contraseña"
|
||||||
|
|
||||||
#: templates/musician/mailboxes.html:43
|
#: templates/musician/mailbox_list.html:43
|
||||||
msgid "New mailbox"
|
msgid "New mailbox"
|
||||||
msgstr "Nuevo buzón de correo"
|
msgstr "Nuevo buzón de correo"
|
||||||
|
|
||||||
#: templates/musician/mailinglists.html:34
|
#: templates/musician/mailinglist_list.html:34
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Activo"
|
msgstr "Activo"
|
||||||
|
|
||||||
#: templates/musician/mailinglists.html:36
|
#: templates/musician/mailinglist_list.html:36
|
||||||
msgid "Inactive"
|
msgid "Inactive"
|
||||||
msgstr "Inactivo"
|
msgstr "Inactivo"
|
||||||
|
|
||||||
|
@ -465,19 +465,19 @@ msgstr "método de pago:"
|
||||||
msgid "Check your last bills"
|
msgid "Check your last bills"
|
||||||
msgstr "Consulta tus últimas facturas"
|
msgstr "Consulta tus últimas facturas"
|
||||||
|
|
||||||
#: templates/musician/saas.html:18
|
#: templates/musician/saas_list.html:18
|
||||||
msgid "Installed on"
|
msgid "Installed on"
|
||||||
msgstr "Instalado en"
|
msgstr "Instalado en"
|
||||||
|
|
||||||
#: templates/musician/saas.html:29
|
#: templates/musician/saas_list.html:29
|
||||||
msgid "Service info"
|
msgid "Service info"
|
||||||
msgstr "Información del servicio"
|
msgstr "Información del servicio"
|
||||||
|
|
||||||
#: templates/musician/saas.html:30
|
#: templates/musician/saas_list.html:30
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "activo"
|
msgstr "activo"
|
||||||
|
|
||||||
#: templates/musician/saas.html:37
|
#: templates/musician/saas_list.html:37
|
||||||
msgid "Open service admin panel"
|
msgid "Open service admin panel"
|
||||||
msgstr "Abre el panel de administración del servicio"
|
msgstr "Abre el panel de administración del servicio"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.http import is_safe_url
|
from django.utils.http import url_has_allowed_host_and_scheme
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic.base import RedirectView, TemplateView
|
from django.views.generic.base import RedirectView, TemplateView
|
||||||
|
@ -153,7 +153,7 @@ def profile_set_language(request, code):
|
||||||
translation.activate(user_language)
|
translation.activate(user_language)
|
||||||
|
|
||||||
redirect_to = request.GET.get('next', '')
|
redirect_to = request.GET.get('next', '')
|
||||||
url_is_safe = is_safe_url(
|
url_is_safe = url_has_allowed_host_and_scheme(
|
||||||
url=redirect_to,
|
url=redirect_to,
|
||||||
allowed_hosts={request.get_host()},
|
allowed_hosts={request.get_host()},
|
||||||
require_https=request.is_secure(),
|
require_https=request.is_secure(),
|
||||||
|
@ -232,7 +232,7 @@ class BillDownloadView(CustomContextMixin, UserTokenRequiredMixin, View):
|
||||||
bill = self.get_object()
|
bill = self.get_object()
|
||||||
|
|
||||||
# TODO(@slamora): implement download as PDF, now only HTML is reachable via link
|
# TODO(@slamora): implement download as PDF, now only HTML is reachable via link
|
||||||
content_type = request.META.get('HTTP_ACCEPT')
|
content_type = request.headers.get('accept')
|
||||||
if content_type == 'application/pdf':
|
if content_type == 'application/pdf':
|
||||||
pdf = html_to_pdf(bill.html or bill.render())
|
pdf = html_to_pdf(bill.html or bill.render())
|
||||||
return HttpResponse(pdf, content_type='application/pdf')
|
return HttpResponse(pdf, content_type='application/pdf')
|
||||||
|
@ -243,7 +243,7 @@ class BillDownloadView(CustomContextMixin, UserTokenRequiredMixin, View):
|
||||||
class AddressListView(ServiceListView):
|
class AddressListView(ServiceListView):
|
||||||
service_class = AddressService
|
service_class = AddressService
|
||||||
model = Address
|
model = Address
|
||||||
template_name = "musician/addresses.html"
|
template_name = "musician/address_list.html"
|
||||||
extra_context = {
|
extra_context = {
|
||||||
# Translators: This message appears on the page title
|
# Translators: This message appears on the page title
|
||||||
'title': _('Mail addresses'),
|
'title': _('Mail addresses'),
|
||||||
|
@ -317,7 +317,7 @@ class AddressDeleteView(CustomContextMixin, UserTokenRequiredMixin, DeleteView):
|
||||||
class MailingListsView(ServiceListView):
|
class MailingListsView(ServiceListView):
|
||||||
service_class = MailinglistService
|
service_class = MailinglistService
|
||||||
model = List
|
model = List
|
||||||
template_name = "musician/mailinglists.html"
|
template_name = "musician/mailinglist_list.html"
|
||||||
extra_context = {
|
extra_context = {
|
||||||
# Translators: This message appears on the page title
|
# Translators: This message appears on the page title
|
||||||
'title': _('Mailing lists'),
|
'title': _('Mailing lists'),
|
||||||
|
@ -348,7 +348,7 @@ class MailingListsView(ServiceListView):
|
||||||
class MailboxListView(ServiceListView):
|
class MailboxListView(ServiceListView):
|
||||||
service_class = MailboxService
|
service_class = MailboxService
|
||||||
model = Mailbox
|
model = Mailbox
|
||||||
template_name = "musician/mailboxes.html"
|
template_name = "musician/mailbox_list.html"
|
||||||
extra_context = {
|
extra_context = {
|
||||||
# Translators: This message appears on the page title
|
# Translators: This message appears on the page title
|
||||||
'title': _('Mailboxes'),
|
'title': _('Mailboxes'),
|
||||||
|
@ -447,7 +447,7 @@ class DatabasesView(ServiceListView):
|
||||||
class SaasListView(ServiceListView):
|
class SaasListView(ServiceListView):
|
||||||
service_class = SaasService
|
service_class = SaasService
|
||||||
model = SaaS
|
model = SaaS
|
||||||
template_name = "musician/saas.html"
|
template_name = "musician/saas_list.html"
|
||||||
extra_context = {
|
extra_context = {
|
||||||
# Translators: This message appears on the page title
|
# Translators: This message appears on the page title
|
||||||
'title': _('Software as a Service'),
|
'title': _('Software as a Service'),
|
||||||
|
@ -496,7 +496,7 @@ class DomainUpdateRecordView(CustomContextMixin, UserTokenRequiredMixin, UpdateV
|
||||||
|
|
||||||
class DomainDeleteRecordView(CustomContextMixin, UserTokenRequiredMixin, DeleteView):
|
class DomainDeleteRecordView(CustomContextMixin, UserTokenRequiredMixin, DeleteView):
|
||||||
model = Record
|
model = Record
|
||||||
template_name = "musician/record_confirm_delete.html"
|
template_name = "musician/record_check_delete.html"
|
||||||
pk_url_kwarg = "record_pk"
|
pk_url_kwarg = "record_pk"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -545,7 +545,7 @@ class LoginView(FormView):
|
||||||
self.redirect_field_name,
|
self.redirect_field_name,
|
||||||
self.request.GET.get(self.redirect_field_name, '')
|
self.request.GET.get(self.redirect_field_name, '')
|
||||||
)
|
)
|
||||||
url_is_safe = is_safe_url(
|
url_is_safe = url_has_allowed_host_and_scheme(
|
||||||
url=redirect_to,
|
url=redirect_to,
|
||||||
allowed_hosts={self.request.get_host()},
|
allowed_hosts={self.request.get_host()},
|
||||||
require_https=self.request.is_secure(),
|
require_https=self.request.is_secure(),
|
||||||
|
|
|
@ -6,7 +6,6 @@ from orchestra.utils.python import AttrDict
|
||||||
from .backends import ServiceBackend, ServiceController, replace
|
from .backends import ServiceBackend, ServiceController, replace
|
||||||
|
|
||||||
|
|
||||||
default_app_config = 'orchestra.contrib.orchestration.apps.OrchestrationConfig'
|
|
||||||
|
|
||||||
|
|
||||||
class Operation():
|
class Operation():
|
||||||
|
|
|
@ -28,6 +28,7 @@ STATE_COLORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Route)
|
||||||
class RouteAdmin(ExtendedModelAdmin):
|
class RouteAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'display_backend', 'host', 'match', 'display_model', 'display_actions', 'run_async',
|
'display_backend', 'host', 'match', 'display_model', 'display_actions', 'run_async',
|
||||||
|
@ -49,20 +50,24 @@ class RouteAdmin(ExtendedModelAdmin):
|
||||||
|
|
||||||
display_backend = display_plugin_field('backend')
|
display_backend = display_plugin_field('backend')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("model")
|
||||||
|
)
|
||||||
def display_model(self, route):
|
def display_model(self, route):
|
||||||
try:
|
try:
|
||||||
return route.backend_class.model
|
return route.backend_class.model
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return mark_safe("<span style='color: red;'>NOT AVAILABLE</span>")
|
return mark_safe("<span style='color: red;'>NOT AVAILABLE</span>")
|
||||||
display_model.short_description = _("model")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("actions")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_actions(self, route):
|
def display_actions(self, route):
|
||||||
try:
|
try:
|
||||||
return '<br>'.join(route.backend_class.get_actions())
|
return '<br>'.join(route.backend_class.get_actions())
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return "<span style='color: red;'>NOT AVAILABLE</span>"
|
return "<span style='color: red;'>NOT AVAILABLE</span>"
|
||||||
display_actions.short_description = _("actions")
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Provides dynamic help text on backend form field """
|
""" Provides dynamic help text on backend form field """
|
||||||
|
@ -113,13 +118,15 @@ class BackendOperationInline(admin.TabularInline):
|
||||||
'all': ('orchestra/css/hide-inline-id.css',)
|
'all': ('orchestra/css/hide-inline-id.css',)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Instance")
|
||||||
|
)
|
||||||
def instance_link(self, operation):
|
def instance_link(self, operation):
|
||||||
link = admin_link('instance')(self, operation)
|
link = admin_link('instance')(self, operation)
|
||||||
if link == '---':
|
if link == '---':
|
||||||
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
return _("Deleted {0}").format(operation.instance_repr or '-'.join(
|
||||||
(escape(operation.content_type), escape(operation.object_id))))
|
(escape(operation.content_type), escape(operation.object_id))))
|
||||||
return link
|
return link
|
||||||
instance_link.short_description = _("Instance")
|
|
||||||
|
|
||||||
def has_add_permission(self, *args, **kwargs):
|
def has_add_permission(self, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
@ -129,6 +136,7 @@ class BackendOperationInline(admin.TabularInline):
|
||||||
return queryset.prefetch_related('instance')
|
return queryset.prefetch_related('instance')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(BackendLog)
|
||||||
class BackendLogAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
class BackendLogAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'backend', 'server_link', 'display_state', 'exit_code',
|
'id', 'backend', 'server_link', 'display_state', 'exit_code',
|
||||||
|
@ -170,19 +178,24 @@ class BackendLogAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Server)
|
||||||
class ServerAdmin(ExtendedModelAdmin):
|
class ServerAdmin(ExtendedModelAdmin):
|
||||||
list_display = ('name', 'address', 'os', 'display_ping', 'display_uptime')
|
list_display = ('name', 'address', 'os', 'display_ping', 'display_uptime')
|
||||||
list_filter = ('os',)
|
list_filter = ('os',)
|
||||||
actions = (orchestrate,)
|
actions = (orchestrate,)
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Ping")
|
||||||
|
)
|
||||||
def display_ping(self, instance):
|
def display_ping(self, instance):
|
||||||
return mark_safe(self._remote_state[instance.pk][0])
|
return mark_safe(self._remote_state[instance.pk][0])
|
||||||
display_ping.short_description = _("Ping")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Uptime")
|
||||||
|
)
|
||||||
def display_uptime(self, instance):
|
def display_uptime(self, instance):
|
||||||
return mark_safe(self._remote_state[instance.pk][1])
|
return mark_safe(self._remote_state[instance.pk][1])
|
||||||
display_uptime.short_description = _("Uptime")
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
""" Order by structured name and imporve performance """
|
""" Order by structured name and imporve performance """
|
||||||
|
@ -191,6 +204,3 @@ class ServerAdmin(ExtendedModelAdmin):
|
||||||
self._remote_state = retrieve_state(qs)
|
self._remote_state = retrieve_state(qs)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
admin.site.register(Server, ServerAdmin)
|
|
||||||
admin.site.register(BackendLog, BackendLogAdmin)
|
|
||||||
admin.site.register(Route, RouteAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.orders.apps.OrdersConfig'
|
|
|
@ -50,6 +50,7 @@ class MetricStorageInline(admin.TabularInline):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Order)
|
||||||
class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'display_description', 'service_link', 'account_link', 'content_object_link',
|
'display_description', 'service_link', 'account_link', 'content_object_link',
|
||||||
|
@ -112,11 +113,17 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
display_registered_on = admin_date('registered_on')
|
display_registered_on = admin_date('registered_on')
|
||||||
display_cancelled_on = admin_date('cancelled_on')
|
display_cancelled_on = admin_date('cancelled_on')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Description"),
|
||||||
|
ordering='description',
|
||||||
|
)
|
||||||
def display_description(self, order):
|
def display_description(self, order):
|
||||||
return format_html(order.description[:64])
|
return format_html(order.description[:64])
|
||||||
display_description.short_description = _("Description")
|
|
||||||
display_description.admin_order_field = 'description'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Content object"),
|
||||||
|
ordering='content_object_repr',
|
||||||
|
)
|
||||||
def content_object_link(self, order):
|
def content_object_link(self, order):
|
||||||
if order.content_object:
|
if order.content_object:
|
||||||
try:
|
try:
|
||||||
|
@ -128,9 +135,10 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
return format_html('<a href="{url}">{description}</a>',
|
return format_html('<a href="{url}">{description}</a>',
|
||||||
url=url, description=description)
|
url=url, description=description)
|
||||||
return order.content_object_repr
|
return order.content_object_repr
|
||||||
content_object_link.short_description = _("Content object")
|
|
||||||
content_object_link.admin_order_field = 'content_object_repr'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Bills")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def bills_links(self, order):
|
def bills_links(self, order):
|
||||||
bills = []
|
bills = []
|
||||||
|
@ -138,8 +146,11 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
for line in order.lines.select_related('bill').distinct('bill'):
|
for line in order.lines.select_related('bill').distinct('bill'):
|
||||||
bills.append(make_link(line.bill))
|
bills.append(make_link(line.bill))
|
||||||
return '<br>'.join(bills)
|
return '<br>'.join(bills)
|
||||||
bills_links.short_description = _("Bills")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("billed until"),
|
||||||
|
ordering='billed_until',
|
||||||
|
)
|
||||||
def display_billed_until(self, order):
|
def display_billed_until(self, order):
|
||||||
billed_until = order.billed_until
|
billed_until = order.billed_until
|
||||||
red = False
|
red = False
|
||||||
|
@ -160,9 +171,10 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
'<span title="{raw}" {color}>{human}</span>',
|
'<span title="{raw}" {color}>{human}</span>',
|
||||||
raw=escape(str(billed_until)), color=color, human=human,
|
raw=escape(str(billed_until)), color=color, human=human,
|
||||||
)
|
)
|
||||||
display_billed_until.short_description = _("billed until")
|
|
||||||
display_billed_until.admin_order_field = 'billed_until'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Metric")
|
||||||
|
)
|
||||||
def display_metric(self, order):
|
def display_metric(self, order):
|
||||||
"""
|
"""
|
||||||
dispalys latest metric value, don't uses latest() because not loosing prefetch_related
|
dispalys latest metric value, don't uses latest() because not loosing prefetch_related
|
||||||
|
@ -172,7 +184,6 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return ''
|
return ''
|
||||||
return metric.value
|
return metric.value
|
||||||
display_metric.short_description = _("Metric")
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
|
@ -197,11 +208,10 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
# return OrderFilterChangeList
|
# return OrderFilterChangeList
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(MetricStorage)
|
||||||
class MetricStorageAdmin(admin.ModelAdmin):
|
class MetricStorageAdmin(admin.ModelAdmin):
|
||||||
list_display = ('order', 'value', 'created_on', 'updated_on')
|
list_display = ('order', 'value', 'created_on', 'updated_on')
|
||||||
list_filter = ('order__service',)
|
list_filter = ('order__service',)
|
||||||
raw_id_fields = ('order',)
|
raw_id_fields = ('order',)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Order, OrderAdmin)
|
|
||||||
admin.site.register(MetricStorage, MetricStorageAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.payments.apps.PaymentsConfig'
|
|
|
@ -32,6 +32,7 @@ PROCESS_STATE_COLORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(PaymentSource)
|
||||||
class PaymentSourceAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class PaymentSourceAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('label', 'method', 'number', 'account_link', 'is_active')
|
list_display = ('label', 'method', 'number', 'account_link', 'is_active')
|
||||||
list_filter = ('method', 'is_active')
|
list_filter = ('method', 'is_active')
|
||||||
|
@ -69,6 +70,7 @@ class TransactionInline(admin.TabularInline):
|
||||||
return qs.select_related('source', 'bill')
|
return qs.select_related('source', 'bill')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Transaction)
|
||||||
class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'bill_link', 'account_link', 'source_link', 'display_created_at',
|
'id', 'bill_link', 'account_link', 'source_link', 'display_created_at',
|
||||||
|
@ -156,16 +158,19 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
return []
|
return []
|
||||||
return [action for action in actions if action.__name__ not in exclude]
|
return [action for action in actions if action.__name__ not in exclude]
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("State"),
|
||||||
|
ordering='state',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_state(self, obj):
|
def display_state(self, obj):
|
||||||
state = admin_colored('state', colors=STATE_COLORS)(obj)
|
state = admin_colored('state', colors=STATE_COLORS)(obj)
|
||||||
help_text = obj.get_state_help()
|
help_text = obj.get_state_help()
|
||||||
state = state.replace('<span ', '<span title="%s" ' % help_text)
|
state = state.replace('<span ', '<span title="%s" ' % help_text)
|
||||||
return state
|
return state
|
||||||
display_state.admin_order_field = 'state'
|
|
||||||
display_state.short_description = _("State")
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(TransactionProcess)
|
||||||
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'file_url', 'display_transactions', 'display_state', 'display_created_at',
|
'id', 'file_url', 'display_transactions', 'display_state', 'display_created_at',
|
||||||
|
@ -184,11 +189,16 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
display_state = admin_colored('state', colors=PROCESS_STATE_COLORS)
|
display_state = admin_colored('state', colors=PROCESS_STATE_COLORS)
|
||||||
display_created_at = admin_date('created_at', short_description=_("Created"))
|
display_created_at = admin_date('created_at', short_description=_("Created"))
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
ordering='file'
|
||||||
|
)
|
||||||
def file_url(self, process):
|
def file_url(self, process):
|
||||||
if process.file:
|
if process.file:
|
||||||
return format_html('<a href="{}">{}</a>', process.file.url, process.file.name)
|
return format_html('<a href="{}">{}</a>', process.file.url, process.file.name)
|
||||||
file_url.admin_order_field = 'file'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Transactions")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_transactions(self, process):
|
def display_transactions(self, process):
|
||||||
ids = []
|
ids = []
|
||||||
|
@ -208,7 +218,6 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
url = reverse('admin:payments_transaction_changelist')
|
url = reverse('admin:payments_transaction_changelist')
|
||||||
url += '?process_id=%i' % process.id
|
url += '?process_id=%i' % process.id
|
||||||
return '<a href="%s">%s</a>' % (url, transactions)
|
return '<a href="%s">%s</a>' % (url, transactions)
|
||||||
display_transactions.short_description = _("Transactions")
|
|
||||||
|
|
||||||
def has_add_permission(self, *args, **kwargs):
|
def has_add_permission(self, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
@ -240,6 +249,3 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
helpers.post_delete_processes(self, request, related_transactions)
|
helpers.post_delete_processes(self, request, related_transactions)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(PaymentSource, PaymentSourceAdmin)
|
|
||||||
admin.site.register(Transaction, TransactionAdmin)
|
|
||||||
admin.site.register(TransactionProcess, TransactionProcessAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.plans.apps.PlansConfig'
|
|
|
@ -18,6 +18,7 @@ class RateInline(admin.TabularInline):
|
||||||
ordering = ('service', 'plan', 'quantity')
|
ordering = ('service', 'plan', 'quantity')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Plan)
|
||||||
class PlanAdmin(ExtendedModelAdmin):
|
class PlanAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'name', 'is_default', 'is_combinable', 'allow_multiple', 'is_active', 'num_contracts',
|
'name', 'is_default', 'is_combinable', 'allow_multiple', 'is_active', 'num_contracts',
|
||||||
|
@ -30,19 +31,22 @@ class PlanAdmin(ExtendedModelAdmin):
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
inlines = [RateInline]
|
inlines = [RateInline]
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Contracts"),
|
||||||
|
ordering='contracts__count',
|
||||||
|
)
|
||||||
def num_contracts(self, plan):
|
def num_contracts(self, plan):
|
||||||
num = plan.contracts__count
|
num = plan.contracts__count
|
||||||
url = reverse('admin:plans_contractedplan_changelist')
|
url = reverse('admin:plans_contractedplan_changelist')
|
||||||
url += '?plan__name={}'.format(plan.name)
|
url += '?plan__name={}'.format(plan.name)
|
||||||
return format_html('<a href="{0}">{1}</a>', url, num)
|
return format_html('<a href="{0}">{1}</a>', url, num)
|
||||||
num_contracts.short_description = _("Contracts")
|
|
||||||
num_contracts.admin_order_field = 'contracts__count'
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(PlanAdmin, self).get_queryset(request)
|
qs = super(PlanAdmin, self).get_queryset(request)
|
||||||
return qs.annotate(models.Count('contracts', distinct=True))
|
return qs.annotate(models.Count('contracts', distinct=True))
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ContractedPlan)
|
||||||
class ContractedPlanAdmin(AccountAdminMixin, admin.ModelAdmin):
|
class ContractedPlanAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||||
list_display = ('id', 'plan_link', 'account_link')
|
list_display = ('id', 'plan_link', 'account_link')
|
||||||
list_filter = ('plan__name',)
|
list_filter = ('plan__name',)
|
||||||
|
@ -53,7 +57,5 @@ class ContractedPlanAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||||
plan_link = admin_link('plan')
|
plan_link = admin_link('plan')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Plan, PlanAdmin)
|
|
||||||
admin.site.register(ContractedPlan, ContractedPlanAdmin)
|
|
||||||
|
|
||||||
insertattr(Service, 'inlines', RateInline)
|
insertattr(Service, 'inlines', RateInline)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from .backends import ServiceMonitor
|
from .backends import ServiceMonitor
|
||||||
|
|
||||||
|
|
||||||
default_app_config = 'orchestra.contrib.resources.apps.ResourcesConfig'
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.utils.translation import ngettext, gettext_lazy as _
|
||||||
|
|
||||||
def run_monitor(modeladmin, request, queryset):
|
def run_monitor(modeladmin, request, queryset):
|
||||||
""" Resource and ResourceData run monitors """
|
""" Resource and ResourceData run monitors """
|
||||||
referer = request.META.get('HTTP_REFERER')
|
referer = request.headers.get('referer')
|
||||||
run_async = modeladmin.model.monitor.__defaults__[0]
|
run_async = modeladmin.model.monitor.__defaults__[0]
|
||||||
logs = set()
|
logs = set()
|
||||||
for resource in queryset:
|
for resource in queryset:
|
||||||
|
|
|
@ -29,6 +29,7 @@ from .forms import ResourceForm
|
||||||
from .models import Resource, ResourceData, MonitorData
|
from .models import Resource, ResourceData, MonitorData
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Resource)
|
||||||
class ResourceAdmin(ExtendedModelAdmin):
|
class ResourceAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'verbose_name', 'content_type', 'aggregation', 'on_demand',
|
'id', 'verbose_name', 'content_type', 'aggregation', 'on_demand',
|
||||||
|
@ -103,14 +104,17 @@ class ResourceAdmin(ExtendedModelAdmin):
|
||||||
return super(ResourceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(ResourceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Content object"),
|
||||||
|
ordering='content_object_repr',
|
||||||
|
)
|
||||||
def content_object_link(data):
|
def content_object_link(data):
|
||||||
ct = data.content_type
|
ct = data.content_type
|
||||||
url = reverse('admin:%s_%s_change' % (ct.app_label, ct.model), args=(data.object_id,))
|
url = reverse('admin:%s_%s_change' % (ct.app_label, ct.model), args=(data.object_id,))
|
||||||
return format_html('<a href="{}">{}</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'
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ResourceData)
|
||||||
class ResourceDataAdmin(ExtendedModelAdmin):
|
class ResourceDataAdmin(ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'resource_link', content_object_link, 'allocated', 'display_used',
|
'id', 'resource_link', content_object_link, 'allocated', 'display_used',
|
||||||
|
@ -151,13 +155,15 @@ class ResourceDataAdmin(ExtendedModelAdmin):
|
||||||
),
|
),
|
||||||
] + urls
|
] + urls
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Used"),
|
||||||
|
ordering='used',
|
||||||
|
)
|
||||||
def display_used(self, rdata):
|
def display_used(self, rdata):
|
||||||
if rdata.used is None:
|
if rdata.used is None:
|
||||||
return ''
|
return ''
|
||||||
url = reverse('admin:resources_resourcedata_used_monitordata', args=(rdata.pk,))
|
url = reverse('admin:resources_resourcedata_used_monitordata', args=(rdata.pk,))
|
||||||
return format_html('<a href="{}">{} {}</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'
|
|
||||||
|
|
||||||
def has_add_permission(self, *args, **kwargs):
|
def has_add_permission(self, *args, **kwargs):
|
||||||
return False
|
return False
|
||||||
|
@ -193,6 +199,7 @@ class ResourceDataAdmin(ExtendedModelAdmin):
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(MonitorData)
|
||||||
class MonitorDataAdmin(ExtendedModelAdmin):
|
class MonitorDataAdmin(ExtendedModelAdmin):
|
||||||
list_display = ('id', 'monitor', content_object_link, 'display_created', 'value')
|
list_display = ('id', 'monitor', content_object_link, 'display_created', 'value')
|
||||||
list_filter = ('monitor', ResourceDataListFilter)
|
list_filter = ('monitor', ResourceDataListFilter)
|
||||||
|
@ -227,9 +234,6 @@ class MonitorDataAdmin(ExtendedModelAdmin):
|
||||||
return queryset.prefetch_related('content_object')
|
return queryset.prefetch_related('content_object')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Resource, ResourceAdmin)
|
|
||||||
admin.site.register(ResourceData, ResourceDataAdmin)
|
|
||||||
admin.site.register(MonitorData, MonitorDataAdmin)
|
|
||||||
|
|
||||||
|
|
||||||
# Mokey-patching
|
# Mokey-patching
|
||||||
|
@ -303,6 +307,9 @@ def resource_inline_factory(resources):
|
||||||
self.verbose_name_plural = mark_safe(_("Resources") + ' ' + link)
|
self.verbose_name_plural = mark_safe(_("Resources") + ' ' + link)
|
||||||
return super(ResourceInline, self).get_fieldsets(request, obj)
|
return super(ResourceInline, self).get_fieldsets(request, obj)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Used")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_used(self, rdata):
|
def display_used(self, rdata):
|
||||||
update = ''
|
update = ''
|
||||||
|
@ -328,7 +335,6 @@ def resource_inline_factory(resources):
|
||||||
if rdata.resource.monitors:
|
if rdata.resource.monitors:
|
||||||
return _("Unknonw %s %s") % (update, history)
|
return _("Unknonw %s %s") % (update, history)
|
||||||
return _("No monitor")
|
return _("No monitor")
|
||||||
display_used.short_description = _("Used")
|
|
||||||
|
|
||||||
def has_add_permission(self, *args, **kwargs):
|
def has_add_permission(self, *args, **kwargs):
|
||||||
""" Hidde add another """
|
""" Hidde add another """
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.saas.apps.SaaSConfig'
|
|
|
@ -18,6 +18,7 @@ from .models import SaaS
|
||||||
from .services import SoftwareService
|
from .services import SoftwareService
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SaaS)
|
||||||
class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'service', 'display_url', 'account_link', 'display_active')
|
list_display = ('name', 'service', 'display_url', 'account_link', 'display_active')
|
||||||
list_filter = ('service', IsActiveListFilter, CustomURLListFilter)
|
list_filter = ('service', IsActiveListFilter, CustomURLListFilter)
|
||||||
|
@ -28,6 +29,10 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
||||||
plugin_title = 'Software as a Service'
|
plugin_title = 'Software as a Service'
|
||||||
actions = (disable, enable, list_accounts)
|
actions = (disable, enable, list_accounts)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("URL"),
|
||||||
|
ordering='name',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_url(self, saas):
|
def display_url(self, saas):
|
||||||
site_domain = saas.get_site_domain()
|
site_domain = saas.get_site_domain()
|
||||||
|
@ -47,8 +52,6 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
||||||
)
|
)
|
||||||
links.append(link)
|
links.append(link)
|
||||||
return '<br>'.join(links)
|
return '<br>'.join(links)
|
||||||
display_url.short_description = _("URL")
|
|
||||||
display_url.admin_order_field = 'name'
|
|
||||||
|
|
||||||
def get_fields(self, *args, **kwargs):
|
def get_fields(self, *args, **kwargs):
|
||||||
fields = super(SaaSAdmin, self).get_fields(*args, **kwargs)
|
fields = super(SaaSAdmin, self).get_fields(*args, **kwargs)
|
||||||
|
@ -57,4 +60,3 @@ class SaaSAdmin(SelectPluginAdminMixin, ChangePasswordAdminMixin, AccountAdminMi
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(SaaS, SaaSAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.services.apps.ServicesConfig'
|
|
|
@ -15,6 +15,7 @@ from .actions import update_orders, view_help, clone
|
||||||
from .models import Service
|
from .models import Service
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Service)
|
||||||
class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'description', 'content_type', 'handler_type', 'num_orders', 'is_active'
|
'description', 'content_type', 'handler_type', 'num_orders', 'is_active'
|
||||||
|
@ -66,13 +67,15 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
kwargs['widget'] = forms.TextInput(attrs={'size':'160'})
|
kwargs['widget'] = forms.TextInput(attrs={'size':'160'})
|
||||||
return super(ServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(ServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Orders"),
|
||||||
|
ordering='orders__count',
|
||||||
|
)
|
||||||
def num_orders(self, service):
|
def num_orders(self, service):
|
||||||
num = service.orders__count
|
num = service.orders__count
|
||||||
url = reverse('admin:orders_order_changelist')
|
url = reverse('admin:orders_order_changelist')
|
||||||
url += '?service__id__exact=%i&is_active=True' % service.pk
|
url += '?service__id__exact=%i&is_active=True' % service.pk
|
||||||
return format_html('<a href="{}">{}</a>', url, num)
|
return format_html('<a href="{}">{}</a>', url, num)
|
||||||
num_orders.short_description = _("Orders")
|
|
||||||
num_orders.admin_order_field = 'orders__count'
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super(ServiceAdmin, self).get_queryset(request)
|
qs = super(ServiceAdmin, self).get_queryset(request)
|
||||||
|
@ -104,4 +107,3 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
help_view.verbose_name = _("Help")
|
help_view.verbose_name = _("Help")
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Service, ServiceAdmin)
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ from orchestra.core import validators
|
||||||
from orchestra.utils.python import import_class, format_exception
|
from orchestra.utils.python import import_class, format_exception
|
||||||
|
|
||||||
|
|
||||||
default_app_config = 'orchestra.contrib.settings.apps.SettingsConfig'
|
|
||||||
|
|
||||||
|
|
||||||
class Setting(object):
|
class Setting(object):
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.systemusers.apps.SystemUsersConfig'
|
|
|
@ -13,6 +13,7 @@ from .forms import SystemUserCreationForm, SystemUserChangeForm, WebappUserChang
|
||||||
from .models import SystemUser, WebappUsers
|
from .models import SystemUser, WebappUsers
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SystemUser)
|
||||||
class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'username', 'account_link', 'shell', 'display_home', 'display_active', 'display_main'
|
'username', 'account_link', 'shell', 'display_home', 'display_active', 'display_main'
|
||||||
|
@ -45,15 +46,19 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
|
||||||
change_view_actions = (set_permission, create_link)
|
change_view_actions = (set_permission, create_link)
|
||||||
actions = (disable, enable, list_accounts) + change_view_actions
|
actions = (disable, enable, list_accounts) + change_view_actions
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Main"),
|
||||||
|
boolean=True,
|
||||||
|
)
|
||||||
def display_main(self, user):
|
def display_main(self, user):
|
||||||
return user.is_main
|
return user.is_main
|
||||||
display_main.short_description = _("Main")
|
|
||||||
display_main.boolean = True
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Home"),
|
||||||
|
ordering='home',
|
||||||
|
)
|
||||||
def display_home(self, user):
|
def display_home(self, user):
|
||||||
return user.get_home()
|
return user.get_home()
|
||||||
display_home.short_description = _("Home")
|
|
||||||
display_home.admin_order_field = 'home'
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
form = super(SystemUserAdmin, self).get_form(request, obj, **kwargs)
|
form = super(SystemUserAdmin, self).get_form(request, obj, **kwargs)
|
||||||
|
@ -79,6 +84,7 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(WebappUsers)
|
||||||
class WebappUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
class WebappUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'username', 'account_link', 'home', 'target_server'
|
'username', 'account_link', 'home', 'target_server'
|
||||||
|
@ -107,5 +113,3 @@ class WebappUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
|
||||||
ordering = ('-id',)
|
ordering = ('-id',)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(SystemUser, SystemUserAdmin)
|
|
||||||
admin.site.register(WebappUsers, WebappUserAdmin)
|
|
|
@ -2,4 +2,3 @@ from . import settings
|
||||||
from .decorators import task, periodic_task, keep_state, apply_async
|
from .decorators import task, periodic_task, keep_state, apply_async
|
||||||
|
|
||||||
|
|
||||||
default_app_config = 'orchestra.contrib.tasks.apps.TasksConfig'
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.vps.apps.VPSConfig'
|
|
|
@ -10,6 +10,7 @@ from orchestra.forms import UserCreationForm, NonStoredUserChangeForm
|
||||||
from .models import VPS
|
from .models import VPS
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(VPS)
|
||||||
class VPSAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class VPSAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('hostname', 'type', 'template', 'display_active', 'account_link')
|
list_display = ('hostname', 'type', 'template', 'display_active', 'account_link')
|
||||||
list_filter = ('type', IsActiveListFilter, 'template')
|
list_filter = ('type', IsActiveListFilter, 'template')
|
||||||
|
@ -44,4 +45,3 @@ class VPSAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
return 'root@%s' % obj.hostname
|
return 'root@%s' % obj.hostname
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(VPS, VPSAdmin)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.webapps.apps.WebAppsConfig'
|
|
|
@ -74,6 +74,7 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(WebApp)
|
||||||
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'name', 'display_type', 'display_detail', 'display_websites', 'account_link', 'target_server',
|
'name', 'display_type', 'display_detail', 'display_websites', 'account_link', 'target_server',
|
||||||
|
@ -91,6 +92,9 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
|
|
||||||
display_type = display_plugin_field('type')
|
display_type = display_plugin_field('type')
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("user sftp")
|
||||||
|
)
|
||||||
def display_sftpuser(self, obj):
|
def display_sftpuser(self, obj):
|
||||||
salida = ""
|
salida = ""
|
||||||
if obj.sftpuser is None:
|
if obj.sftpuser is None:
|
||||||
|
@ -99,8 +103,10 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
url = resolve_url(admin_urlname(WebappUsers._meta, 'change'), obj.sftpuser.id)
|
url = resolve_url(admin_urlname(WebappUsers._meta, 'change'), obj.sftpuser.id)
|
||||||
salida += f'<a href="{url}">{obj.sftpuser}</a> <br />'
|
salida += f'<a href="{url}">{obj.sftpuser}</a> <br />'
|
||||||
return mark_safe(salida)
|
return mark_safe(salida)
|
||||||
display_sftpuser.short_description = _("user sftp")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("web sites")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_websites(self, webapp):
|
def display_websites(self, webapp):
|
||||||
websites = []
|
websites = []
|
||||||
|
@ -118,14 +124,15 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
plus = '<strong style="color:green; font-size:12px">+</strong>'
|
plus = '<strong style="color:green; font-size:12px">+</strong>'
|
||||||
websites.append('<a href="%s">%s%s</a>' % (add_url, plus, gettext("Add website")))
|
websites.append('<a href="%s">%s%s</a>' % (add_url, plus, gettext("Add website")))
|
||||||
return '<br>'.join(websites)
|
return '<br>'.join(websites)
|
||||||
display_websites.short_description = _("web sites")
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("detail")
|
||||||
|
)
|
||||||
def display_detail(self, webapp):
|
def display_detail(self, webapp):
|
||||||
try:
|
try:
|
||||||
return webapp.type_instance.get_detail()
|
return webapp.type_instance.get_detail()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return mark_safe("<span style='color:red;'>Not available</span>")
|
return mark_safe("<span style='color:red;'>Not available</span>")
|
||||||
display_detail.short_description = _("detail")
|
|
||||||
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
|
@ -155,5 +162,4 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
)
|
)
|
||||||
return super().response_add(request, obj, post_url_continue)
|
return super().response_add(request, obj, post_url_continue)
|
||||||
|
|
||||||
admin.site.register(WebApp, WebAppAdmin)
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
default_app_config = 'orchestra.contrib.websites.apps.WebsitesConfig'
|
|
|
@ -51,13 +51,16 @@ class ContentInline(AccountAdminMixin, admin.TabularInline):
|
||||||
webapp_link = admin_link('webapp', popup=True)
|
webapp_link = admin_link('webapp', popup=True)
|
||||||
webapp_link.short_description = _("Web App")
|
webapp_link.short_description = _("Web App")
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Web App type")
|
||||||
|
)
|
||||||
def webapp_type(self, content):
|
def webapp_type(self, content):
|
||||||
if not content.pk:
|
if not content.pk:
|
||||||
return ''
|
return ''
|
||||||
return content.webapp.get_type_display()
|
return content.webapp.get_type_display()
|
||||||
webapp_type.short_description = _("Web App type")
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Website)
|
||||||
class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'name', 'display_domains', 'display_webapps', 'account_link', 'target_server', 'display_active'
|
'name', 'display_domains', 'display_webapps', 'account_link', 'target_server', 'display_active'
|
||||||
|
@ -80,6 +83,10 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
search_fields = ('name', 'account__username', 'domains__name', 'content__webapp__name')
|
search_fields = ('name', 'account__username', 'domains__name', 'content__webapp__name')
|
||||||
actions = (disable, enable, list_accounts)
|
actions = (disable, enable, list_accounts)
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("domains"),
|
||||||
|
ordering='domains',
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_domains(self, website):
|
def display_domains(self, website):
|
||||||
domains = []
|
domains = []
|
||||||
|
@ -87,9 +94,10 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
url = '%s://%s' % (website.get_protocol(), domain)
|
url = '%s://%s' % (website.get_protocol(), domain)
|
||||||
domains.append('<a href="%s">%s</a>' % (url, url))
|
domains.append('<a href="%s">%s</a>' % (url, url))
|
||||||
return '<br>'.join(domains)
|
return '<br>'.join(domains)
|
||||||
display_domains.short_description = _("domains")
|
|
||||||
display_domains.admin_order_field = 'domains'
|
|
||||||
|
|
||||||
|
@admin.display(
|
||||||
|
description=_("Web apps")
|
||||||
|
)
|
||||||
@mark_safe
|
@mark_safe
|
||||||
def display_webapps(self, website):
|
def display_webapps(self, website):
|
||||||
webapps = []
|
webapps = []
|
||||||
|
@ -106,7 +114,6 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
webapp_info = format_html('<a href="{}" title="{}">{}</a> {}', url, detail, name, site_link)
|
webapp_info = format_html('<a href="{}" title="{}">{}</a> {}', url, detail, name, site_link)
|
||||||
webapps.append(webapp_info)
|
webapps.append(webapp_info)
|
||||||
return '<br>'.join(webapps)
|
return '<br>'.join(webapps)
|
||||||
display_webapps.short_description = _("Web apps")
|
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -136,4 +143,3 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
return formsets, inline_instances
|
return formsets, inline_instances
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Website, WebsiteAdmin)
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ class SelectPluginAdminMixin(object):
|
||||||
if not plugin_value and request.method == 'POST':
|
if not plugin_value and request.method == 'POST':
|
||||||
# HACK baceuse django add_preserved_filters removes extising queryargs
|
# HACK baceuse django add_preserved_filters removes extising queryargs
|
||||||
value = re.search(r"%s=([^&^']+)[&']" % self.plugin_field,
|
value = re.search(r"%s=([^&^']+)[&']" % self.plugin_field,
|
||||||
request.META.get('HTTP_REFERER', ''))
|
request.headers.get('referer', ''))
|
||||||
if value:
|
if value:
|
||||||
plugin_value = value.groups()[0]
|
plugin_value = value.groups()[0]
|
||||||
return plugin_value
|
return plugin_value
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.conf.urls import include, url
|
from django.urls import include, path, re_path
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from rest_framework.authtoken.views import obtain_auth_token
|
from rest_framework.authtoken.views import obtain_auth_token
|
||||||
|
|
||||||
|
@ -15,13 +15,13 @@ api.autodiscover()
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Admin
|
# Admin
|
||||||
url(r'^admin/', admin.site.urls),
|
re_path(r'^admin/', admin.site.urls),
|
||||||
url(r'^admin_tools/', include('admin_tools.urls')),
|
path('admin_tools/', include('admin_tools.urls')),
|
||||||
# REST API
|
# REST API
|
||||||
url(r'^api/', include(api.router.urls)),
|
path('api/', include(api.router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
url(r'^api-token-auth/', obtain_auth_token, name='api-token-auth'),
|
re_path(r'^api-token-auth/', obtain_auth_token, name='api-token-auth'),
|
||||||
url(r'^media/(.+)/(.+)/(.+)/(.+)/(.+)$', serve_private_media, name='private-media'),
|
re_path(r'^media/(.+)/(.+)/(.+)/(.+)/(.+)$', serve_private_media, name='private-media'),
|
||||||
# url(r'search', 'orchestra.views.search', name='search'),
|
# url(r'search', 'orchestra.views.search', name='search'),
|
||||||
# MUSICIAN
|
# MUSICIAN
|
||||||
path('panel/', include('orchestra.contrib.musician.urls')),
|
path('panel/', include('orchestra.contrib.musician.urls')),
|
||||||
|
@ -31,5 +31,5 @@ urlpatterns = [
|
||||||
if isinstalled('debug_toolbar'):
|
if isinstalled('debug_toolbar'):
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
url(r'^__debug__/', include(debug_toolbar.urls)),
|
path('__debug__/', include(debug_toolbar.urls)),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
Django==2.2.24
|
|
||||||
django-fluent-dashboard==1.0.1
|
Django==3.2.23
|
||||||
django-admin-tools==0.9.1
|
django-fluent-dashboard==2.0
|
||||||
|
django-admin-tools==0.9.3
|
||||||
|
django-extensions==3.2.3
|
||||||
|
django-celery==3.3.1
|
||||||
|
celery>=3.1.15,<4.0
|
||||||
|
kombu==3.0.37
|
||||||
django-bootstrap4
|
django-bootstrap4
|
||||||
django-extensions==3.1.3
|
|
||||||
django-celery==3.2.1
|
|
||||||
celery==3.1.23
|
|
||||||
kombu==3.0.35
|
|
||||||
billiard==3.3.0.23
|
billiard==3.3.0.23
|
||||||
Markdown==3.3.4
|
Markdown==3.5.1
|
||||||
djangorestframework==3.12.4
|
djangorestframework==3.14.0
|
||||||
Pygments==2.9.0
|
Pygments==2.17.2
|
||||||
django-filter==2.4.0
|
django-filter==23.4
|
||||||
jsonfield==3.1.0
|
jsonfield==3.1.0
|
||||||
python-dateutil>=2.7.0
|
python-dateutil==2.8.2
|
||||||
passlib==1.7.4
|
passlib==1.7.4
|
||||||
django-iban==0.3.0
|
django-iban==0.3.1
|
||||||
requests
|
requests
|
||||||
phonenumbers==8.12.27
|
phonenumbers==8.13.26
|
||||||
django-countries
|
django-countries
|
||||||
django-localflavor==3.1
|
django-localflavor==4.0
|
||||||
amqp
|
amqp
|
||||||
anyjson
|
anyjson
|
||||||
pytz
|
pytz
|
||||||
|
|
Loading…
Reference in New Issue