django.core.urlresolvers moved to django.urls

Django 2.0
This commit is contained in:
Santiago L 2021-04-21 14:27:18 +02:00
parent 2b06652a5b
commit eadc06d4c5
43 changed files with 428 additions and 428 deletions

View File

@ -3,7 +3,7 @@ from collections import OrderedDict
from functools import update_wrapper from functools import update_wrapper
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -56,7 +56,7 @@ def search(request):
if service.search: if service.search:
models.add(service.model) models.add(service.model)
model_name_map[service.model._meta.model_name] = service.model model_name_map[service.model._meta.model_name] = service.model
# Account direct access # Account direct access
if search_term.endswith('!'): if search_term.endswith('!'):
from ..contrib.accounts.models import Account from ..contrib.accounts.models import Account

View File

@ -1,4 +1,4 @@
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from fluent_dashboard import dashboard, appsettings from fluent_dashboard import dashboard, appsettings
from fluent_dashboard.modules import CmsAppIconList from fluent_dashboard.modules import CmsAppIconList
@ -11,7 +11,7 @@ class AppDefaultIconList(CmsAppIconList):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.icons = kwargs.pop('icons') self.icons = kwargs.pop('icons')
super(AppDefaultIconList, self).__init__(*args, **kwargs) super(AppDefaultIconList, self).__init__(*args, **kwargs)
def get_icon_for_model(self, app_name, model_name, default=None): def get_icon_for_model(self, app_name, model_name, default=None):
icon = self.icons.get('.'.join((app_name, model_name))) icon = self.icons.get('.'.join((app_name, model_name)))
return super(AppDefaultIconList, self).get_icon_for_model(app_name, model_name, default=icon) return super(AppDefaultIconList, self).get_icon_for_model(app_name, model_name, default=icon)
@ -19,7 +19,7 @@ class AppDefaultIconList(CmsAppIconList):
class OrchestraIndexDashboard(dashboard.FluentIndexDashboard): class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
""" Gets application modules from services, accounts and administration registries """ """ Gets application modules from services, accounts and administration registries """
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(dashboard.FluentIndexDashboard, self).__init__(**kwargs) super(dashboard.FluentIndexDashboard, self).__init__(**kwargs)
self.children.append(self.get_personal_module()) self.children.append(self.get_personal_module())
@ -27,7 +27,7 @@ class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
recent_actions = self.get_recent_actions_module() recent_actions = self.get_recent_actions_module()
recent_actions.enabled = True recent_actions.enabled = True
self.children.append(recent_actions) self.children.append(recent_actions)
def process_registered_view(self, module, view_name, options): def process_registered_view(self, module, view_name, options):
app_name, name = view_name.split('_')[:-1] app_name, name = view_name.split('_')[:-1]
module.icons['.'.join((app_name, name))] = options.get('icon') module.icons['.'.join((app_name, name))] = options.get('icon')
@ -47,7 +47,7 @@ class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
'title': options.get('verbose_name_plural'), 'title': options.get('verbose_name_plural'),
'url': add_url, 'url': add_url,
}) })
def get_application_modules(self): def get_application_modules(self):
modules = [] modules = []
# Honor settings override, hacky. I Know # Honor settings override, hacky. I Know

View File

@ -1,7 +1,7 @@
from copy import deepcopy from copy import deepcopy
from admin_tools.menu import items, Menu from admin_tools.menu import items, Menu
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -16,7 +16,7 @@ def api_link(context):
opts = context['cl'].opts opts = context['cl'].opts
else: else:
return reverse('api-root') return reverse('api-root')
if 'object_id' in context: if 'object_id' in context:
object_id = context['object_id'] object_id = context['object_id']
try: try:
return reverse('%s-detail' % opts.model_name, args=[object_id]) return reverse('%s-detail' % opts.model_name, args=[object_id])
@ -42,7 +42,7 @@ def process_registry(register):
item = items.MenuItem(name, url) item = items.MenuItem(name, url)
item.options = options item.options = options
return item return item
childrens = {} childrens = {}
for model, options in register.get().items(): for model, options in register.get().items():
if options.get('menu', True): if options.get('menu', True):
@ -68,7 +68,7 @@ def process_registry(register):
class OrchestraMenu(Menu): class OrchestraMenu(Menu):
template = 'admin/orchestra/menu.html' template = 'admin/orchestra/menu.html'
def init_with_context(self, context): def init_with_context(self, context):
self.children = [ self.children = [
# items.MenuItem( # items.MenuItem(

View File

@ -6,7 +6,7 @@ from functools import wraps
from django.conf import settings from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.db import models from django.db import models
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone from django.utils import timezone

View File

@ -1,4 +1,4 @@
from django.core.urlresolvers import NoReverseMatch from django.urls import NoReverseMatch
from rest_framework.reverse import reverse from rest_framework.reverse import reverse

View File

@ -4,7 +4,7 @@ from django.contrib import messages
from django.contrib.admin import helpers from django.contrib.admin import helpers
from django.contrib.admin.utils import NestedObjects, quote from django.contrib.admin.utils import NestedObjects, quote
from django.contrib.auth import get_permission_codename from django.contrib.auth import get_permission_codename
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.db import router from django.db import router
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
@ -53,14 +53,14 @@ def service_report(modeladmin, request, queryset):
fields.append((model, name)) fields.append((model, name))
fields = sorted(fields, key=lambda f: f[0]._meta.verbose_name_plural.lower()) fields = sorted(fields, key=lambda f: f[0]._meta.verbose_name_plural.lower())
fields = [field for model, field in fields] fields = [field for model, field in fields]
for account in queryset.prefetch_related(*fields): for account in queryset.prefetch_related(*fields):
items = [] items = []
for field in fields: for field in fields:
related_manager = getattr(account, field) related_manager = getattr(account, field)
items.append((related_manager.model._meta, related_manager.all())) items.append((related_manager.model._meta, related_manager.all()))
accounts.append((account, items)) accounts.append((account, items))
context = { context = {
'accounts': accounts, 'accounts': accounts,
'date': timezone.now().today() 'date': timezone.now().today()
@ -71,21 +71,21 @@ def service_report(modeladmin, request, queryset):
def delete_related_services(modeladmin, request, queryset): def delete_related_services(modeladmin, request, queryset):
opts = modeladmin.model._meta opts = modeladmin.model._meta
app_label = opts.app_label app_label = opts.app_label
using = router.db_for_write(modeladmin.model) using = router.db_for_write(modeladmin.model)
collector = NestedObjects(using=using) collector = NestedObjects(using=using)
collector.collect(queryset) collector.collect(queryset)
registered_services = services.get() registered_services = services.get()
related_services = [] related_services = []
to_delete = [] to_delete = []
admin_site = modeladmin.admin_site admin_site = modeladmin.admin_site
def format(obj, account=False): def format(obj, account=False):
has_admin = obj.__class__ in admin_site._registry has_admin = obj.__class__ in admin_site._registry
opts = obj._meta opts = obj._meta
no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), force_text(obj)) no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), force_text(obj))
if has_admin: if has_admin:
try: try:
admin_url = reverse( admin_url = reverse(
@ -95,7 +95,7 @@ def delete_related_services(modeladmin, request, queryset):
except NoReverseMatch: except NoReverseMatch:
# Change url doesn't exist -- don't display link to edit # Change url doesn't exist -- don't display link to edit
return no_edit_link return no_edit_link
# Display a link to the admin page. # Display a link to the admin page.
context = (capfirst(opts.verbose_name), admin_url, obj) context = (capfirst(opts.verbose_name), admin_url, obj)
if account: if account:
@ -106,7 +106,7 @@ def delete_related_services(modeladmin, request, queryset):
# Don't display link to edit, because it either has no # Don't display link to edit, because it either has no
# admin or is edited inline. # admin or is edited inline.
return no_edit_link return no_edit_link
def format_nested(objs, result): def format_nested(objs, result):
if isinstance(objs, list): if isinstance(objs, list):
current = [] current = []
@ -115,7 +115,7 @@ def delete_related_services(modeladmin, request, queryset):
result.append(current) result.append(current)
else: else:
result.append(format(objs)) result.append(format(objs))
for nested in collector.nested(): for nested in collector.nested():
if isinstance(nested, list): if isinstance(nested, list):
# Is lists of objects # Is lists of objects
@ -141,7 +141,7 @@ def delete_related_services(modeladmin, request, queryset):
# Prevent the deletion of the main system user, which will delete the account # Prevent the deletion of the main system user, which will delete the account
main_systemuser = nested.main_systemuser main_systemuser = nested.main_systemuser
related_services.append(format(nested, account=True)) related_services.append(format(nested, account=True))
# The user has already confirmed the deletion. # The user has already confirmed the deletion.
# Do the deletion and return a None to display the change list view again. # Do the deletion and return a None to display the change list view again.
if request.POST.get('post'): if request.POST.get('post'):
@ -165,12 +165,12 @@ def delete_related_services(modeladmin, request, queryset):
modeladmin.message_user(request, msg, messages.SUCCESS) modeladmin.message_user(request, msg, messages.SUCCESS)
# Return None to display the change list page again. # Return None to display the change list page again.
return None return None
if len(queryset) == 1: if len(queryset) == 1:
objects_name = force_text(opts.verbose_name) objects_name = force_text(opts.verbose_name)
else: else:
objects_name = force_text(opts.verbose_name_plural) objects_name = force_text(opts.verbose_name_plural)
model_count = {} model_count = {}
for model, objs in collector.model_objs.items(): for model, objs in collector.model_objs.items():
count = 0 count = 0
@ -220,10 +220,10 @@ def disable_selected(modeladmin, request, queryset, disable=True):
n) n)
) )
return None return None
user = request.user user = request.user
admin_site = modeladmin.admin_site admin_site = modeladmin.admin_site
def format(obj): def format(obj):
has_admin = obj.__class__ in admin_site._registry has_admin = obj.__class__ in admin_site._registry
opts = obj._meta opts = obj._meta
@ -238,7 +238,7 @@ def disable_selected(modeladmin, request, queryset, disable=True):
except NoReverseMatch: except NoReverseMatch:
# Change url doesn't exist -- don't display link to edit # Change url doesn't exist -- don't display link to edit
return no_edit_link return no_edit_link
p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts)) p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts))
if not user.has_perm(p): if not user.has_perm(p):
perms_needed.add(opts.verbose_name) perms_needed.add(opts.verbose_name)
@ -249,19 +249,19 @@ def disable_selected(modeladmin, request, queryset, disable=True):
# Don't display link to edit, because it either has no # Don't display link to edit, because it either has no
# admin or is edited inline. # admin or is edited inline.
return no_edit_link return no_edit_link
display = [] display = []
for account in queryset: for account in queryset:
current = [] current = []
for related in account.get_services_to_disable(): for related in account.get_services_to_disable():
current.append(format(related)) current.append(format(related))
display.append([format(account), current]) display.append([format(account), current])
if len(queryset) == 1: if len(queryset) == 1:
objects_name = force_text(opts.verbose_name) objects_name = force_text(opts.verbose_name)
else: else:
objects_name = force_text(opts.verbose_name_plural) objects_name = force_text(opts.verbose_name_plural)
context = dict( context = dict(
admin_site.each_context(request), admin_site.each_context(request),
action_name='disable_selected' if disable else 'enable_selected', action_name='disable_selected' if disable else 'enable_selected',

View File

@ -8,7 +8,7 @@ from django.conf.urls import url
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.admin.utils import unquote from django.contrib.admin.utils import unquote
from django.contrib.auth import admin as auth from django.contrib.auth import admin as auth
from django.core.urlresolvers import reverse from django.urls import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.templatetags.static import static from django.templatetags.static import static
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -71,15 +71,15 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
) )
change_view_actions = (disable_selected, service_report, enable_selected) change_view_actions = (disable_selected, service_report, enable_selected)
ordering = () ordering = ()
main_systemuser_link = admin_link('main_systemuser') main_systemuser_link = admin_link('main_systemuser')
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 """
if db_field.name == 'comments': if db_field.name == 'comments':
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4}) kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4})
return super(AccountAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(AccountAdmin, self).formfield_for_dbfield(db_field, **kwargs)
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):
if not add: if not add:
if request.method == 'GET' and not obj.is_active: if request.method == 'GET' and not obj.is_active:
@ -96,7 +96,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
}) })
return super(AccountAdmin, self).render_change_form( return super(AccountAdmin, self).render_change_form(
request, context, add, change, form_url, obj) request, context, add, change, form_url, obj)
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
fieldsets = super(AccountAdmin, self).get_fieldsets(request, obj) fieldsets = super(AccountAdmin, self).get_fieldsets(request, obj)
if not obj: if not obj:
@ -106,7 +106,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
fieldsets = list(fieldsets) fieldsets = list(fieldsets)
fieldsets.insert(1, (_("Related services"), {'fields': fields})) fieldsets.insert(1, (_("Related services"), {'fields': fields}))
return fieldsets return fieldsets
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
if not change: if not change:
form.save_model(obj) form.save_model(obj)
@ -133,7 +133,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
if msg: if msg:
messages.warning(request, mark_safe(msg % context)) messages.warning(request, mark_safe(msg % context))
super(AccountAdmin, self).save_model(request, obj, form, change) super(AccountAdmin, self).save_model(request, obj, form, change)
def get_change_view_actions(self, obj=None): def get_change_view_actions(self, obj=None):
views = super().get_change_view_actions(obj=obj) views = super().get_change_view_actions(obj=obj)
if obj is not None: if obj is not None:
@ -141,7 +141,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
return [view for view in views if view.url_name != 'enable'] return [view for view in views if view.url_name != 'enable']
return [view for view in views if view.url_name != 'disable'] return [view for view in views if view.url_name != 'disable']
return views return views
def get_actions(self, request): def get_actions(self, request):
actions = super().get_actions(request) actions = super().get_actions(request)
if 'delete_selected' in actions: if 'delete_selected' in actions:
@ -157,7 +157,7 @@ class AccountListAdmin(AccountAdmin):
list_display = ('select_account', 'username', 'type', 'username') list_display = ('select_account', 'username', 'type', 'username')
actions = None actions = None
change_list_template = 'admin/accounts/account/select_account_list.html' change_list_template = 'admin/accounts/account/select_account_list.html'
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
context = { context = {
@ -169,7 +169,7 @@ class AccountListAdmin(AccountAdmin):
select_account.short_description = _("account") select_account.short_description = _("account")
select_account.allow_tags = True select_account.allow_tags = True
select_account.admin_order_field = 'username' 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]
model = request.META['PATH_INFO'].split('/')[-4] model = request.META['PATH_INFO'].split('/')[-4]
@ -206,7 +206,7 @@ class AccountAdminMixin(object):
change_form_template = 'admin/accounts/account/change_form.html' change_form_template = 'admin/accounts/account/change_form.html'
account = None account = None
list_select_related = ('account',) list_select_related = ('account',)
def display_active(self, instance): def display_active(self, instance):
if not instance.is_active: if not instance.is_active:
return '<img src="%s" alt="False">' % static('admin/img/icon-no.svg') return '<img src="%s" alt="False">' % static('admin/img/icon-no.svg')
@ -217,14 +217,14 @@ class AccountAdminMixin(object):
display_active.short_description = _("active") display_active.short_description = _("active")
display_active.allow_tags = True display_active.allow_tags = True
display_active.admin_order_field = 'is_active' display_active.admin_order_field = 'is_active'
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.short_description = _("account")
account_link.allow_tags = True account_link.allow_tags = True
account_link.admin_order_field = 'account__username' 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 """
form = super(AccountAdminMixin, self).get_form(request, obj, **kwargs) form = super(AccountAdminMixin, self).get_form(request, obj, **kwargs)
@ -247,7 +247,7 @@ class AccountAdminMixin(object):
# Not available in POST # Not available in POST
form.initial_account = self.get_changeform_initial_data(request).get('account') form.initial_account = self.get_changeform_initial_data(request).get('account')
return form return form
def get_fields(self, request, obj=None): def get_fields(self, request, obj=None):
""" remove account or account_link depending on the case """ """ remove account or account_link depending on the case """
fields = super(AccountAdminMixin, self).get_fields(request, obj) fields = super(AccountAdminMixin, self).get_fields(request, obj)
@ -263,13 +263,13 @@ class AccountAdminMixin(object):
except ValueError: except ValueError:
pass pass
return fields return fields
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
""" provide account for filter_by_account_fields """ """ provide account for filter_by_account_fields """
if obj: if obj:
self.account = obj.account self.account = obj.account
return super(AccountAdminMixin, self).get_readonly_fields(request, obj) return super(AccountAdminMixin, self).get_readonly_fields(request, obj)
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
""" Filter by account """ """ Filter by account """
formfield = super(AccountAdminMixin, self).formfield_for_dbfield(db_field, **kwargs) formfield = super(AccountAdminMixin, self).formfield_for_dbfield(db_field, **kwargs)
@ -277,14 +277,14 @@ class AccountAdminMixin(object):
if self.account: if self.account:
# Hack widget render in order to append ?account=id to the add url # Hack widget render in order to append ?account=id to the add url
old_render = formfield.widget.render old_render = formfield.widget.render
def render(*args, **kwargs): def render(*args, **kwargs):
output = old_render(*args, **kwargs) output = old_render(*args, **kwargs)
output = output.replace('/add/"', '/add/?account=%s"' % self.account.pk) output = output.replace('/add/"', '/add/?account=%s"' % self.account.pk)
with_qargs = r'/add/?\1&account=%s"' % self.account.pk with_qargs = r'/add/?\1&account=%s"' % self.account.pk
output = re.sub(r'/add/\?([^".]*)"', with_qargs, output) output = re.sub(r'/add/\?([^".]*)"', with_qargs, output)
return mark_safe(output) return mark_safe(output)
formfield.widget.render = render formfield.widget.render = render
# Filter related object by account # Filter related object by account
formfield.queryset = formfield.queryset.filter(account=self.account) formfield.queryset = formfield.queryset.filter(account=self.account)
@ -302,21 +302,21 @@ class AccountAdminMixin(object):
formfield.initial = 1 formfield.initial = 1
formfield.queryset = formfield.queryset.order_by('username') formfield.queryset = formfield.queryset.order_by('username')
return formfield return formfield
def get_formset(self, request, obj=None, **kwargs): def get_formset(self, request, obj=None, **kwargs):
""" provides form.account for convinience """ """ provides form.account for convinience """
formset = super(AccountAdminMixin, self).get_formset(request, obj, **kwargs) formset = super(AccountAdminMixin, self).get_formset(request, obj, **kwargs)
formset.form.account = self.account formset.form.account = self.account
formset.account = self.account formset.account = self.account
return formset return formset
def get_account_from_preserve_filters(self, request): def get_account_from_preserve_filters(self, request):
preserved_filters = self.get_preserved_filters(request) preserved_filters = self.get_preserved_filters(request)
preserved_filters = dict(parse_qsl(preserved_filters)) preserved_filters = dict(parse_qsl(preserved_filters))
cl_filters = preserved_filters.get('_changelist_filters') cl_filters = preserved_filters.get('_changelist_filters')
if cl_filters: if cl_filters:
return dict(parse_qsl(cl_filters)).get('account') return dict(parse_qsl(cl_filters)).get('account')
def changeform_view(self, request, object_id=None, form_url='', extra_context=None): def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
account_id = self.get_account_from_preserve_filters(request) account_id = self.get_account_from_preserve_filters(request)
if not object_id: if not object_id:
@ -331,7 +331,7 @@ class AccountAdminMixin(object):
context.update(extra_context or {}) context.update(extra_context or {})
return super(AccountAdminMixin, self).changeform_view( return super(AccountAdminMixin, self).changeform_view(
request, object_id, form_url=form_url, extra_context=context) request, object_id, form_url=form_url, extra_context=context)
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
account_id = request.GET.get('account') account_id = request.GET.get('account')
context = {} context = {}
@ -367,7 +367,7 @@ class SelectAccountAdminMixin(AccountAdminMixin):
account = Account.objects.get(pk=request.GET['account']) account = Account.objects.get(pk=request.GET['account'])
[setattr(inline, 'account', account) for inline in inlines] [setattr(inline, 'account', account) for inline in inlines]
return inlines return inlines
def get_urls(self): def get_urls(self):
""" Hooks select account url """ """ Hooks select account url """
urls = super(AccountAdminMixin, self).get_urls() urls = super(AccountAdminMixin, self).get_urls()
@ -381,7 +381,7 @@ class SelectAccountAdminMixin(AccountAdminMixin):
name='%s_%s_select_account' % info), name='%s_%s_select_account' % info),
] ]
return select_urls + urls return select_urls + urls
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url='', extra_context=None):
""" Redirects to select account view if required """ """ Redirects to select account view if required """
if request.user.is_superuser: if request.user.is_superuser:
@ -406,7 +406,7 @@ class SelectAccountAdminMixin(AccountAdminMixin):
return super(AccountAdminMixin, self).add_view( return super(AccountAdminMixin, self).add_view(
request, form_url=form_url, extra_context=context) request, form_url=form_url, extra_context=context)
return HttpResponseRedirect('./select-account/?%s' % request.META['QUERY_STRING']) return HttpResponseRedirect('./select-account/?%s' % request.META['QUERY_STRING'])
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
""" """
Given a model instance save it to the database. Given a model instance save it to the database.

View File

@ -5,7 +5,7 @@ from datetime import date
from django.contrib import messages from django.contrib import messages
from django.contrib.admin import helpers from django.contrib.admin import helpers
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import transaction from django.db import transaction
from django.forms.models import modelformset_factory from django.forms.models import modelformset_factory
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
@ -179,7 +179,7 @@ def undo_billing(modeladmin, request, queryset):
group[line.order].append(line) group[line.order].append(line)
except KeyError: except KeyError:
group[line.order] = [line] group[line.order] = [line]
# Validate # Validate
for order, lines in group.items(): for order, lines in group.items():
prev = None prev = None
@ -211,7 +211,7 @@ def undo_billing(modeladmin, request, queryset):
messages.error(request, "Order does not have lines!.") messages.error(request, "Order does not have lines!.")
order.billed_until = billed_until order.billed_until = billed_until
order.billed_on = billed_on order.billed_on = billed_on
# Commit changes # Commit changes
norders, nlines = 0, 0 norders, nlines = 0, 0
for order, lines in group.items(): for order, lines in group.items():
@ -221,7 +221,7 @@ def undo_billing(modeladmin, request, queryset):
# TODO update order history undo billing # TODO update order history undo billing
order.save(update_fields=('billed_until', 'billed_on')) order.save(update_fields=('billed_until', 'billed_on'))
norders += 1 norders += 1
messages.success(request, _("%(norders)s orders and %(nlines)s lines undoed.") % { messages.success(request, _("%(norders)s orders and %(nlines)s lines undoed.") % {
'nlines': nlines, 'nlines': nlines,
'norders': norders 'norders': norders

View File

@ -2,7 +2,7 @@ from django import forms
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.admin.utils import unquote from django.contrib.admin.utils import unquote
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.db.models import F, Sum, Prefetch from django.db.models import F, Sum, Prefetch
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
@ -39,18 +39,18 @@ PAYMENT_STATE_COLORS = {
class BillSublineInline(admin.TabularInline): class BillSublineInline(admin.TabularInline):
model = BillSubline model = BillSubline
fields = ('description', 'total', 'type') fields = ('description', 'total', 'type')
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)
if obj and not obj.bill.is_open: if obj and not obj.bill.is_open:
return self.get_fields(request) return self.get_fields(request)
return fields return fields
def get_max_num(self, request, obj=None): def get_max_num(self, request, obj=None):
if obj and not obj.bill.is_open: if obj and not obj.bill.is_open:
return 0 return 0
return super().get_max_num(request, obj) return super().get_max_num(request, obj)
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
if obj and not obj.bill.is_open: if obj and not obj.bill.is_open:
return False return False
@ -64,9 +64,9 @@ class BillLineInline(admin.TabularInline):
'subtotal', 'display_total', 'subtotal', 'display_total',
) )
readonly_fields = ('display_total', 'order_link') readonly_fields = ('display_total', 'order_link')
order_link = admin_link('order', display='pk') order_link = admin_link('order', display='pk')
def display_total(self, line): def display_total(self, line):
if line.pk: if line.pk:
total = line.compute_total() total = line.compute_total()
@ -79,7 +79,7 @@ class BillLineInline(admin.TabularInline):
return '<a href="%s">%s</a>' % (url, total) return '<a href="%s">%s</a>' % (url, total)
display_total.short_description = _("Total") display_total.short_description = _("Total")
display_total.allow_tags = True display_total.allow_tags = True
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 """
if db_field.name == 'description': if db_field.name == 'description':
@ -87,7 +87,7 @@ class BillLineInline(admin.TabularInline):
elif db_field.name not in ('start_on', 'end_on'): elif db_field.name not in ('start_on', 'end_on'):
kwargs['widget'] = forms.TextInput(attrs={'size':'6'}) kwargs['widget'] = forms.TextInput(attrs={'size':'6'})
return super().formfield_for_dbfield(db_field, **kwargs) return super().formfield_for_dbfield(db_field, **kwargs)
def get_queryset(self, request): def get_queryset(self, request):
qs = super().get_queryset(request) qs = super().get_queryset(request)
return qs.prefetch_related('sublines').select_related('order') return qs.prefetch_related('sublines').select_related('order')
@ -96,14 +96,14 @@ class BillLineInline(admin.TabularInline):
class ClosedBillLineInline(BillLineInline): class ClosedBillLineInline(BillLineInline):
# TODO reimplement as nested inlines when upstream # TODO reimplement as nested inlines when upstream
# https://code.djangoproject.com/ticket/9025 # https://code.djangoproject.com/ticket/9025
fields = ( fields = (
'display_description', 'order_link', 'start_on', 'end_on', 'rate', 'quantity', 'tax', 'display_description', 'order_link', 'start_on', 'end_on', 'rate', 'quantity', 'tax',
'display_subtotal', 'display_total' 'display_subtotal', 'display_total'
) )
readonly_fields = fields readonly_fields = fields
can_delete = False can_delete = False
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():
@ -111,7 +111,7 @@ class ClosedBillLineInline(BillLineInline):
return '<br>'.join(descriptions) return '<br>'.join(descriptions)
display_description.short_description = _("Description") display_description.short_description = _("Description")
display_description.allow_tags = True display_description.allow_tags = True
def display_subtotal(self, line): def display_subtotal(self, line):
subtotals = ['&nbsp;' + str(line.subtotal)] subtotals = ['&nbsp;' + str(line.subtotal)]
for subline in line.sublines.all(): for subline in line.sublines.all():
@ -119,13 +119,13 @@ class ClosedBillLineInline(BillLineInline):
return '<br>'.join(subtotals) return '<br>'.join(subtotals)
display_subtotal.short_description = _("Subtotal") display_subtotal.short_description = _("Subtotal")
display_subtotal.allow_tags = True display_subtotal.allow_tags = True
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") display_total.short_description = _("Total")
display_total.allow_tags = True display_total.allow_tags = True
def has_add_permission(self, request): def has_add_permission(self, request):
return False return False
@ -158,28 +158,28 @@ class BillLineAdmin(admin.ModelAdmin):
list_select_related = ('bill', 'bill__account') list_select_related = ('bill', 'bill__account')
search_fields = ('description', 'bill__number') search_fields = ('description', 'bill__number')
inlines = (BillSublineInline,) inlines = (BillSublineInline,)
account_link = admin_link('bill__account') account_link = admin_link('bill__account')
bill_link = admin_link('bill') bill_link = admin_link('bill')
order_link = admin_link('order') order_link = admin_link('order')
amended_line_link = admin_link('amended_line') amended_line_link = admin_link('amended_line')
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.short_description = _("Is open")
display_is_open.boolean = True display_is_open.boolean = True
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.short_description = _("Sublines")
display_sublinetotal.admin_order_field = 'subline_total' display_sublinetotal.admin_order_field = 'subline_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.short_description = _("Total")
display_total.admin_order_field = 'computed_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)
if obj and not obj.bill.is_open: if obj and not obj.bill.is_open:
@ -188,7 +188,7 @@ class BillLineAdmin(admin.ModelAdmin):
'subtotal', 'order_billed_on', 'order_billed_until' 'subtotal', 'order_billed_on', 'order_billed_until'
] ]
return fields return fields
def get_queryset(self, request): def get_queryset(self, request):
qs = super().get_queryset(request) qs = super().get_queryset(request)
qs = qs.annotate( qs = qs.annotate(
@ -196,7 +196,7 @@ class BillLineAdmin(admin.ModelAdmin):
computed_total=(F('subtotal') + Sum(Coalesce('sublines__total', 0))) * (1+F('tax')/100), computed_total=(F('subtotal') + Sum(Coalesce('sublines__total', 0))) * (1+F('tax')/100),
) )
return qs return qs
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
if obj and not obj.bill.is_open: if obj and not obj.bill.is_open:
return False return False
@ -209,7 +209,7 @@ class BillLineManagerAdmin(BillLineAdmin):
if self.bill_ids: if self.bill_ids:
return qset.filter(bill_id__in=self.bill_ids) return qset.filter(bill_id__in=self.bill_ids)
return qset return qset
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
GET_copy = request.GET.copy() GET_copy = request.GET.copy()
bill_ids = GET_copy.pop('ids', None) bill_ids = GET_copy.pop('ids', None)
@ -304,9 +304,9 @@ class AmendInline(BillAdminMixin, admin.TabularInline):
verbose_name_plural = _("Amends") verbose_name_plural = _("Amends")
can_delete = False can_delete = False
extra = 0 extra = 0
self_link = admin_link('__str__') self_link = admin_link('__str__')
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
@ -354,12 +354,12 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
'closed_on_display', 'updated_on_display', 'display_total_with_subtotals', 'closed_on_display', 'updated_on_display', 'display_total_with_subtotals',
) )
date_hierarchy = 'closed_on' date_hierarchy = 'closed_on'
created_on_display = admin_date('created_on', short_description=_("Created")) created_on_display = admin_date('created_on', short_description=_("Created"))
closed_on_display = admin_date('closed_on', short_description=_("Closed")) closed_on_display = admin_date('closed_on', short_description=_("Closed"))
updated_on_display = admin_date('updated_on', short_description=_("Updated")) updated_on_display = admin_date('updated_on', short_description=_("Updated"))
amend_of_link = admin_link('amend_of') amend_of_link = admin_link('amend_of')
# def amend_links(self, bill): # def amend_links(self, bill):
# links = [] # links = []
# for amend in bill.amends.all(): # for amend in bill.amends.all():
@ -368,19 +368,19 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
# return '<br>'.join(links) # return '<br>'.join(links)
# amend_links.short_description = _("Amends") # amend_links.short_description = _("Amends")
# amend_links.allow_tags = True # amend_links.allow_tags = True
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.admin_order_field = 'lines__count'
num_lines.short_description = _("lines") num_lines.short_description = _("lines")
def display_total(self, bill): def display_total(self, bill):
currency = settings.BILLS_CURRENCY.lower() currency = settings.BILLS_CURRENCY.lower()
return '%s &%s;' % (bill.compute_total(), currency) return '%s &%s;' % (bill.compute_total(), currency)
display_total.allow_tags = True display_total.allow_tags = True
display_total.short_description = _("total") display_total.short_description = _("total")
display_total.admin_order_field = 'approx_total' display_total.admin_order_field = 'approx_total'
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)
@ -388,7 +388,7 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
type_link.allow_tags = True type_link.allow_tags = True
type_link.short_description = _("type") type_link.short_description = _("type")
type_link.admin_order_field = '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 """
urls = super().get_urls() urls = super().get_urls()
@ -399,13 +399,13 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
name='bills_bill_manage_lines'), name='bills_bill_manage_lines'),
] ]
return extra_urls + urls return extra_urls + urls
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)
if obj and not obj.is_open: if obj and not obj.is_open:
fields += self.add_fields fields += self.add_fields
return fields return fields
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
fieldsets = super().get_fieldsets(request, obj) fieldsets = super().get_fieldsets(request, obj)
if obj: if obj:
@ -418,7 +418,7 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
if obj.is_open: if obj.is_open:
fieldsets = fieldsets[0:-1] fieldsets = fieldsets[0:-1]
return fieldsets return fieldsets
def get_change_view_actions(self, obj=None): def get_change_view_actions(self, obj=None):
actions = super().get_change_view_actions(obj) actions = super().get_change_view_actions(obj)
exclude = [] exclude = []
@ -428,7 +428,7 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
if obj.type not in obj.AMEND_MAP: if obj.type not in obj.AMEND_MAP:
exclude += ['amend_bills'] exclude += ['amend_bills']
return [action for action in actions if action.__name__ not in exclude] return [action for action in actions if action.__name__ not in exclude]
def get_inline_instances(self, request, obj=None): def get_inline_instances(self, request, obj=None):
cls = type(self) cls = type(self)
if obj and not obj.is_open: if obj and not obj.is_open:
@ -439,7 +439,7 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
else: else:
cls.inlines = [BillLineInline] cls.inlines = [BillLineInline]
return super().get_inline_instances(request, obj) return super().get_inline_instances(request, obj)
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 """
if db_field.name == 'comments': if db_field.name == 'comments':
@ -450,7 +450,7 @@ class BillAdmin(BillAdminMixin, ExtendedModelAdmin):
if db_field.name == 'amend_of': if db_field.name == 'amend_of':
formfield.queryset = formfield.queryset.filter(is_open=False) formfield.queryset = formfield.queryset.filter(is_open=False)
return formfield return formfield
def change_view(self, request, object_id, **kwargs): def change_view(self, request, object_id, **kwargs):
# TODO raise404, here and everywhere # TODO raise404, here and everywhere
bill = self.get_object(request, unquote(object_id)) bill = self.get_object(request, unquote(object_id))
@ -471,7 +471,7 @@ admin.site.register(BillLine, BillLineAdmin)
class BillContactInline(admin.StackedInline): class BillContactInline(admin.StackedInline):
model = BillContact model = BillContact
fields = ('name', 'address', ('city', 'zipcode'), 'country', 'vat') fields = ('name', 'address', ('city', 'zipcode'), 'country', 'vat')
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 """
if db_field.name == 'name': if db_field.name == 'name':

View File

@ -1,5 +1,5 @@
from django.contrib.admin import SimpleListFilter from django.contrib.admin import SimpleListFilter
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db.models import Q from django.db.models import Q
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -11,11 +11,11 @@ class BillTypeListFilter(SimpleListFilter):
""" Filter tickets by created_by according to request.user """ """ Filter tickets by created_by according to request.user """
title = 'Type' title = 'Type'
parameter_name = '' parameter_name = ''
def __init__(self, request, *args, **kwargs): def __init__(self, request, *args, **kwargs):
super(BillTypeListFilter, self).__init__(request, *args, **kwargs) super(BillTypeListFilter, self).__init__(request, *args, **kwargs)
self.request = request self.request = request
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('bill', _("All")), ('bill', _("All")),
@ -25,13 +25,13 @@ class BillTypeListFilter(SimpleListFilter):
('amendmentfee', _("Amendment fee")), ('amendmentfee', _("Amendment fee")),
('amendmentinvoice', _("Amendment invoice")), ('amendmentinvoice', _("Amendment invoice")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
return queryset return queryset
def value(self): def value(self):
return self.request.path.split('/')[-2] return self.request.path.split('/')[-2]
def choices(self, cl): def choices(self, cl):
query = self.request.GET.urlencode() query = self.request.GET.urlencode()
for lookup, title in self.lookup_choices: for lookup, title in self.lookup_choices:
@ -45,7 +45,7 @@ class BillTypeListFilter(SimpleListFilter):
class TotalListFilter(SimpleListFilter): class TotalListFilter(SimpleListFilter):
title = _("total") title = _("total")
parameter_name = 'total' parameter_name = 'total'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('gt', mark_safe("total &gt; 0")), ('gt', mark_safe("total &gt; 0")),
@ -53,7 +53,7 @@ class TotalListFilter(SimpleListFilter):
('eq', "total = 0"), ('eq', "total = 0"),
('ne', mark_safe("total &ne; 0")), ('ne', mark_safe("total &ne; 0")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
if self.value() == 'gt': if self.value() == 'gt':
return queryset.filter(approx_total__gt=0) return queryset.filter(approx_total__gt=0)
@ -70,13 +70,13 @@ class HasBillContactListFilter(SimpleListFilter):
""" Filter Nodes by group according to request.user """ """ Filter Nodes by group according to request.user """
title = _("has bill contact") title = _("has bill contact")
parameter_name = 'bill' parameter_name = 'bill'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('True', _("Yes")), ('True', _("Yes")),
('False', _("No")), ('False', _("No")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
if self.value() == 'True': if self.value() == 'True':
return queryset.filter(billcontact__isnull=False) return queryset.filter(billcontact__isnull=False)
@ -87,7 +87,7 @@ class HasBillContactListFilter(SimpleListFilter):
class PaymentStateListFilter(SimpleListFilter): class PaymentStateListFilter(SimpleListFilter):
title = _("payment state") title = _("payment state")
parameter_name = 'payment_state' parameter_name = 'payment_state'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('OPEN', _("Open")), ('OPEN', _("Open")),
@ -95,7 +95,7 @@ class PaymentStateListFilter(SimpleListFilter):
('PENDING', _("Pending")), ('PENDING', _("Pending")),
('BAD_DEBT', _("Bad debt")), ('BAD_DEBT', _("Bad debt")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
# FIXME use queryset.computed_total instead of approx_total, bills.admin.BillAdmin.get_queryset # FIXME use queryset.computed_total instead of approx_total, bills.admin.BillAdmin.get_queryset
Transaction = queryset.model.transactions.field.remote_field.related_model Transaction = queryset.model.transactions.field.remote_field.related_model
@ -137,7 +137,7 @@ class PaymentStateListFilter(SimpleListFilter):
class AmendedListFilter(SimpleListFilter): class AmendedListFilter(SimpleListFilter):
title = _("amended") title = _("amended")
parameter_name = 'amended' parameter_name = 'amended'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('3', _("Closed amends")), ('3', _("Closed amends")),
@ -145,7 +145,7 @@ class AmendedListFilter(SimpleListFilter):
('1', _("Any amends")), ('1', _("Any amends")),
('0', _("No amends")), ('0', _("No amends")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
if self.value() is None: if self.value() is None:
return queryset return queryset

View File

@ -1,5 +1,5 @@
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe

View File

@ -1,7 +1,7 @@
import datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from django.core.urlresolvers import reverse from django.urls import reverse
from django.core.validators import ValidationError, RegexValidator from django.core.validators import ValidationError, RegexValidator
from django.db import models from django.db import models
from django.db.models import F, Sum from django.db.models import F, Sum
@ -36,13 +36,13 @@ class BillContact(models.Model):
choices=settings.BILLS_CONTACT_COUNTRIES, choices=settings.BILLS_CONTACT_COUNTRIES,
default=settings.BILLS_CONTACT_DEFAULT_COUNTRY) default=settings.BILLS_CONTACT_DEFAULT_COUNTRY)
vat = models.CharField(_("VAT number"), max_length=64) vat = models.CharField(_("VAT number"), max_length=64)
def __str__(self): def __str__(self):
return self.name return self.name
def get_name(self): def get_name(self):
return self.name or self.account.get_full_name() return self.name or self.account.get_full_name()
def clean(self): def clean(self):
self.vat = self.vat.strip() self.vat = self.vat.strip()
self.city = self.city.strip() self.city = self.city.strip()
@ -99,7 +99,7 @@ class Bill(models.Model):
INVOICE: AMENDMENTINVOICE, INVOICE: AMENDMENTINVOICE,
FEE: AMENDMENTFEE, FEE: AMENDMENTFEE,
} }
number = models.CharField(_("number"), max_length=16, unique=True, blank=True) number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
account = models.ForeignKey('accounts.Account', verbose_name=_("account"), account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
related_name='%(class)s') related_name='%(class)s')
@ -115,37 +115,37 @@ class Bill(models.Model):
# total = models.DecimalField(max_digits=12, decimal_places=2, null=True) # total = models.DecimalField(max_digits=12, decimal_places=2, null=True)
comments = models.TextField(_("comments"), blank=True) comments = models.TextField(_("comments"), blank=True)
html = models.TextField(_("HTML"), blank=True) html = models.TextField(_("HTML"), blank=True)
objects = BillManager() objects = BillManager()
class Meta: class Meta:
get_latest_by = 'id' get_latest_by = 'id'
def __str__(self): def __str__(self):
return self.number return self.number
@classmethod @classmethod
def get_class_type(cls): def get_class_type(cls):
if cls is models.DEFERRED: if cls is models.DEFERRED:
cls = cls.__base__ cls = cls.__base__
return cls.__name__.upper() return cls.__name__.upper()
@cached_property @cached_property
def total(self): def total(self):
return self.compute_total() return self.compute_total()
@cached_property @cached_property
def seller(self): def seller(self):
return Account.objects.get_main().billcontact return Account.objects.get_main().billcontact
@cached_property @cached_property
def buyer(self): def buyer(self):
return self.account.billcontact return self.account.billcontact
@property @property
def has_multiple_pages(self): def has_multiple_pages(self):
return self.type != self.FEE return self.type != self.FEE
@cached_property @cached_property
def payment_state(self): def payment_state(self):
if self.is_open or self.get_type() == self.PROFORMA: if self.is_open or self.get_type() == self.PROFORMA:
@ -192,7 +192,7 @@ class Bill(models.Model):
elif executed: elif executed:
return self.EXECUTED return self.EXECUTED
return self.BAD_DEBT return self.BAD_DEBT
def clean(self): def clean(self):
if self.amend_of_id: if self.amend_of_id:
errors = {} errors = {}
@ -206,27 +206,27 @@ class Bill(models.Model):
errors['amend_of'] = _("Related invoice is an amendment.") errors['amend_of'] = _("Related invoice is an amendment.")
if errors: if errors:
raise ValidationError(errors) raise ValidationError(errors)
def get_payment_state_display(self): def get_payment_state_display(self):
value = self.payment_state value = self.payment_state
return force_text(dict(self.PAYMENT_STATES).get(value, value)) return force_text(dict(self.PAYMENT_STATES).get(value, value))
def get_current_transaction(self): def get_current_transaction(self):
return self.transactions.exclude_rejected().first() return self.transactions.exclude_rejected().first()
def get_type(self): def get_type(self):
return self.type or self.get_class_type() return self.type or self.get_class_type()
@property @property
def is_amend(self): def is_amend(self):
return self.type in self.AMEND_MAP.values() return self.type in self.AMEND_MAP.values()
def get_amend_type(self): def get_amend_type(self):
amend_type = self.AMEND_MAP.get(self.type) amend_type = self.AMEND_MAP.get(self.type)
if amend_type is None: if amend_type is None:
raise TypeError("%s has no associated amend type." % self.type) raise TypeError("%s has no associated amend type." % self.type)
return amend_type return amend_type
def get_number(self): def get_number(self):
cls = type(self) cls = type(self)
if cls is models.DEFERRED: if cls is models.DEFERRED:
@ -250,16 +250,16 @@ class Bill(models.Model):
zeros = (number_length - len(str(number))) * '0' zeros = (number_length - len(str(number))) * '0'
number = zeros + str(number) number = zeros + str(number)
return '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number) return '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number)
def get_due_date(self, payment=None): def get_due_date(self, payment=None):
now = timezone.now() now = timezone.now()
if payment: if payment:
return now + payment.get_due_delta() return now + payment.get_due_delta()
return now + relativedelta(months=1) return now + relativedelta(months=1)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('admin:bills_bill_view', args=(self.pk,)) return reverse('admin:bills_bill_view', args=(self.pk,))
def close(self, payment=False): def close(self, payment=False):
if not self.is_open: if not self.is_open:
raise TypeError("Bill not in Open state.") raise TypeError("Bill not in Open state.")
@ -278,10 +278,10 @@ class Bill(models.Model):
self.html = self.render(payment=payment) self.html = self.render(payment=payment)
self.save() self.save()
return transaction return transaction
def get_billing_contact_emails(self): def get_billing_contact_emails(self):
return self.account.get_contacts_emails(usages=(Contact.BILLING,)) return self.account.get_contacts_emails(usages=(Contact.BILLING,))
def send(self): def send(self):
pdf = self.as_pdf() pdf = self.as_pdf()
self.account.send_email( self.account.send_email(
@ -298,7 +298,7 @@ class Bill(models.Model):
) )
self.is_sent = True self.is_sent = True
self.save(update_fields=['is_sent']) self.save(update_fields=['is_sent'])
def render(self, payment=False, language=None): def render(self, payment=False, language=None):
with translation.override(language or self.account.language): with translation.override(language or self.account.language):
if payment is False: if payment is False:
@ -325,22 +325,22 @@ class Bill(models.Model):
html = bill_template.render(context) html = bill_template.render(context)
html = html.replace('-pageskip-', '<pdf:nextpage />') html = html.replace('-pageskip-', '<pdf:nextpage />')
return html return html
def as_pdf(self): def as_pdf(self):
html = self.html or self.render() html = self.html or self.render()
return html_to_pdf(html, pagination=self.has_multiple_pages) return html_to_pdf(html, pagination=self.has_multiple_pages)
def updated(self): def updated(self):
self.updated_on = timezone.now() self.updated_on = timezone.now()
self.save(update_fields=('updated_on',)) self.save(update_fields=('updated_on',))
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.type: if not self.type:
self.type = self.get_type() self.type = self.get_type()
if not self.number: if not self.number:
self.number = self.get_number() self.number = self.get_number()
super(Bill, self).save(*args, **kwargs) super(Bill, self).save(*args, **kwargs)
@cached @cached
def compute_subtotals(self): def compute_subtotals(self):
subtotals = {} subtotals = {}
@ -354,21 +354,21 @@ class Bill(models.Model):
for tax, subtotal in subtotals.items(): for tax, subtotal in subtotals.items():
result[tax] = [subtotal, round(tax/100*subtotal, 2)] result[tax] = [subtotal, round(tax/100*subtotal, 2)]
return result return result
@cached @cached
def compute_base(self): def compute_base(self):
bases = self.lines.annotate( bases = self.lines.annotate(
bases=F('subtotal') + Sum(Coalesce('sublines__total', 0)) bases=F('subtotal') + Sum(Coalesce('sublines__total', 0))
) )
return round(bases.aggregate(Sum('bases'))['bases__sum'] or 0, 2) return round(bases.aggregate(Sum('bases'))['bases__sum'] or 0, 2)
@cached @cached
def compute_tax(self): def compute_tax(self):
taxes = self.lines.annotate( taxes = self.lines.annotate(
taxes=(F('subtotal') + Coalesce(Sum('sublines__total'), 0)) * (F('tax')/100) taxes=(F('subtotal') + Coalesce(Sum('sublines__total'), 0)) * (F('tax')/100)
) )
return round(taxes.aggregate(Sum('taxes'))['taxes__sum'] or 0, 2) return round(taxes.aggregate(Sum('taxes'))['taxes__sum'] or 0, 2)
@cached @cached
def compute_total(self): def compute_total(self):
if 'lines' in getattr(self, '_prefetched_objects_cache', ()): if 'lines' in getattr(self, '_prefetched_objects_cache', ()):
@ -435,23 +435,23 @@ class BillLine(models.Model):
# Amendment # Amendment
amended_line = models.ForeignKey('self', verbose_name=_("amended line"), amended_line = models.ForeignKey('self', verbose_name=_("amended line"),
related_name='amendment_lines', null=True, blank=True) related_name='amendment_lines', null=True, blank=True)
class Meta: class Meta:
get_latest_by = 'id' get_latest_by = 'id'
def __str__(self): def __str__(self):
return "#%i" % self.pk if self.pk else self.description return "#%i" % self.pk if self.pk else self.description
def get_verbose_quantity(self): def get_verbose_quantity(self):
return self.verbose_quantity or self.quantity return self.verbose_quantity or self.quantity
def clean(self): def clean(self):
if not self.verbose_quantity: if not self.verbose_quantity:
quantity = str(self.quantity) quantity = str(self.quantity)
# Strip trailing zeros # Strip trailing zeros
if quantity.endswith('0'): if quantity.endswith('0'):
self.verbose_quantity = quantity.strip('0').strip('.') self.verbose_quantity = quantity.strip('0').strip('.')
def get_verbose_period(self): def get_verbose_period(self):
from django.template.defaultfilters import date from django.template.defaultfilters import date
date_format = "N 'y" date_format = "N 'y"
@ -467,7 +467,7 @@ class BillLine(models.Model):
if ini == end: if ini == end:
return ini return ini
return "{ini} / {end}".format(ini=ini, end=end) return "{ini} / {end}".format(ini=ini, end=end)
@cached @cached
def compute_total(self): def compute_total(self):
total = self.subtotal or 0 total = self.subtotal or 0
@ -478,7 +478,7 @@ class BillLine(models.Model):
else: else:
total += self.sublines.aggregate(sub_total=Sum('total'))['sub_total'] or 0 total += self.sublines.aggregate(sub_total=Sum('total'))['sub_total'] or 0
return round(total, 2) return round(total, 2)
def get_absolute_url(self): def get_absolute_url(self):
return change_url(self) return change_url(self)
@ -493,12 +493,12 @@ class BillSubline(models.Model):
(COMPENSATION, _("Compensation")), (COMPENSATION, _("Compensation")),
(OTHER, _("Other")), (OTHER, _("Other")),
) )
# TODO: order info for undoing # TODO: order info for undoing
line = models.ForeignKey(BillLine, verbose_name=_("bill line"), related_name='sublines') line = models.ForeignKey(BillLine, verbose_name=_("bill line"), related_name='sublines')
description = models.CharField(_("description"), max_length=256) description = models.CharField(_("description"), max_length=256)
total = models.DecimalField(max_digits=12, decimal_places=2) total = models.DecimalField(max_digits=12, decimal_places=2)
type = models.CharField(_("type"), max_length=16, choices=TYPES, default=OTHER) type = models.CharField(_("type"), max_length=16, choices=TYPES, default=OTHER)
def __str__(self): def __str__(self):
return "%s %i" % (self.description, self.total) return "%s %i" % (self.description, self.total)

View File

@ -6,7 +6,7 @@ import unittest
import MySQLdb import MySQLdb
from django.conf import settings as djsettings from django.conf import settings as djsettings
from django.core.management.base import CommandError from django.core.management.base import CommandError
from django.core.urlresolvers import reverse from django.urls import reverse
from orchestra.admin.utils import change_url from orchestra.admin.utils import change_url
from orchestra.contrib.orchestration.models import Route, Server from orchestra.contrib.orchestration.models import Route, Server
from orchestra.utils.sys import sshrun from orchestra.utils.sys import sshrun

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.db.models.functions import Concat, Coalesce from django.db.models.functions import Concat, Coalesce
from django.templatetags.static import static from django.templatetags.static import static
@ -32,18 +32,18 @@ class DomainInline(admin.TabularInline):
readonly_fields = ('domain_link', 'display_records', 'account_link') readonly_fields = ('domain_link', 'display_records', 'account_link')
extra = 0 extra = 0
verbose_name_plural = _("Subdomains") verbose_name_plural = _("Subdomains")
domain_link = admin_link('__str__') domain_link = admin_link('__str__')
domain_link.short_description = _("Name") domain_link.short_description = _("Name")
account_link = admin_link('account') account_link = admin_link('account')
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") display_records.short_description = _("Declared records")
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
def get_queryset(self, request): def get_queryset(self, request):
""" Order by structured name and imporve performance """ """ Order by structured name and imporve performance """
qs = super(DomainInline, self).get_queryset(request) qs = super(DomainInline, self).get_queryset(request)
@ -66,9 +66,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
add_form = BatchDomainCreationAdminForm add_form = BatchDomainCreationAdminForm
actions = (edit_records, set_soa, list_accounts) actions = (edit_records, set_soa, list_accounts)
change_view_actions = (view_zone, edit_records) change_view_actions = (view_zone, edit_records)
top_link = admin_link('top') top_link = admin_link('top')
def structured_name(self, domain): def structured_name(self, domain):
if domain.is_top: if domain.is_top:
return domain.name return domain.name
@ -76,13 +76,13 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
structured_name.short_description = _("name") structured_name.short_description = _("name")
structured_name.allow_tags = True structured_name.allow_tags = True
structured_name.admin_order_field = 'structured_name' structured_name.admin_order_field = 'structured_name'
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.short_description = _("Is top")
display_is_top.boolean = True display_is_top.boolean = True
display_is_top.admin_order_field = 'top' display_is_top.admin_order_field = 'top'
def display_websites(self, domain): def display_websites(self, domain):
if apps.isinstalled('orchestra.contrib.websites'): if apps.isinstalled('orchestra.contrib.websites'):
websites = domain.websites.all() websites = domain.websites.all()
@ -107,7 +107,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
display_websites.admin_order_field = 'websites__name' display_websites.admin_order_field = 'websites__name'
display_websites.short_description = _("Websites") display_websites.short_description = _("Websites")
display_websites.allow_tags = True display_websites.allow_tags = True
def display_addresses(self, domain): def display_addresses(self, domain):
if apps.isinstalled('orchestra.contrib.mailboxes'): if apps.isinstalled('orchestra.contrib.mailboxes'):
add_url = reverse('admin:mailboxes_address_add') add_url = reverse('admin:mailboxes_address_add')
@ -127,7 +127,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
display_addresses.short_description = _("Addresses") display_addresses.short_description = _("Addresses")
display_addresses.admin_order_field = 'addresses__count' display_addresses.admin_order_field = 'addresses__count'
display_addresses.allow_tags = True display_addresses.allow_tags = True
def implicit_records(self, domain): def implicit_records(self, domain):
defaults = [] defaults = []
types = set(domain.records.values_list('type', flat=True)) types = set(domain.records.values_list('type', flat=True))
@ -149,7 +149,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
return '<br>'.join(lines) return '<br>'.join(lines)
implicit_records.short_description = _("Implicit records") implicit_records.short_description = _("Implicit records")
implicit_records.allow_tags = True implicit_records.allow_tags = True
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 """
fieldsets = super(DomainAdmin, self).get_fieldsets(request, obj) fieldsets = super(DomainAdmin, self).get_fieldsets(request, obj)
@ -175,13 +175,13 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
if 'top_link' not in existing: if 'top_link' not in existing:
fieldsets[0][1]['fields'].insert(2, 'top_link') fieldsets[0][1]['fields'].insert(2, 'top_link')
return fieldsets return fieldsets
def get_inline_instances(self, request, obj=None): def get_inline_instances(self, request, obj=None):
inlines = super(DomainAdmin, self).get_inline_instances(request, obj) inlines = super(DomainAdmin, self).get_inline_instances(request, obj)
if not obj or not obj.is_top: if not obj or not obj.is_top:
return [inline for inline in inlines if type(inline) != DomainInline] return [inline for inline in inlines if type(inline) != DomainInline]
return inlines return inlines
def get_queryset(self, request): def get_queryset(self, request):
""" Order by structured name and imporve performance """ """ Order by structured name and imporve performance """
qs = super(DomainAdmin, self).get_queryset(request) qs = super(DomainAdmin, self).get_queryset(request)
@ -196,7 +196,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
if apps.isinstalled('orchestra.contrib.mailboxes'): if apps.isinstalled('orchestra.contrib.mailboxes'):
qs = qs.annotate(models.Count('addresses')) qs = qs.annotate(models.Count('addresses'))
return qs return qs
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
""" batch domain creation support """ """ batch domain creation support """
super(DomainAdmin, self).save_model(request, obj, form, change) super(DomainAdmin, self).save_model(request, obj, form, change)
@ -205,7 +205,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
for name in form.extra_names: for name in form.extra_names:
domain = Domain.objects.create(name=name, account_id=obj.account_id) domain = Domain.objects.create(name=name, account_id=obj.account_id)
self.extra_domains.append(domain) self.extra_domains.append(domain)
def save_related(self, request, form, formsets, change): def save_related(self, request, form, formsets, change):
""" batch domain creation support """ """ batch domain creation support """
super(DomainAdmin, self).save_related(request, form, formsets, change) super(DomainAdmin, self).save_related(request, form, formsets, change)

View File

@ -4,7 +4,7 @@ import socket
from functools import partial from functools import partial
from django.conf import settings as djsettings from django.conf import settings as djsettings
from django.core.urlresolvers import reverse from django.urls import reverse
from selenium.webdriver.support.select import Select from selenium.webdriver.support.select import Select
from orchestra.contrib.orchestration.models import Server, Route from orchestra.contrib.orchestration.models import Server, Route
@ -23,7 +23,7 @@ class DomainTestMixin(object):
SLAVE_SERVER = os.environ.get('ORCHESTRA_SLAVE_SERVER', 'localhost') SLAVE_SERVER = os.environ.get('ORCHESTRA_SLAVE_SERVER', 'localhost')
MASTER_SERVER_ADDR = socket.gethostbyname(MASTER_SERVER) MASTER_SERVER_ADDR = socket.gethostbyname(MASTER_SERVER)
SLAVE_SERVER_ADDR = socket.gethostbyname(SLAVE_SERVER) SLAVE_SERVER_ADDR = socket.gethostbyname(SLAVE_SERVER)
def setUp(self): def setUp(self):
djsettings.DEBUG = True djsettings.DEBUG = True
super(DomainTestMixin, self).setUp() super(DomainTestMixin, self).setUp()
@ -53,19 +53,19 @@ class DomainTestMixin(object):
(Record.CNAME, 'external.server.org.'), (Record.CNAME, 'external.server.org.'),
) )
self.django_domain_name = 'django%s.lan' % random_ascii(10) self.django_domain_name = 'django%s.lan' % random_ascii(10)
def add_route(self): def add_route(self):
raise NotImplementedError raise NotImplementedError
def add(self, domain_name, records): def add(self, domain_name, records):
raise NotImplementedError raise NotImplementedError
def delete(self, domain_name, records): def delete(self, domain_name, records):
raise NotImplementedError raise NotImplementedError
def update(self, domain_name, records): def update(self, domain_name, records):
raise NotImplementedError raise NotImplementedError
def validate_add(self, server_addr, domain_name): def validate_add(self, server_addr, domain_name):
context = { context = {
'domain_name': domain_name, 'domain_name': domain_name,
@ -81,7 +81,7 @@ class DomainTestMixin(object):
self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4])
hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER) hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER)
self.assertEqual(hostmaster, soa[5]) self.assertEqual(hostmaster, soa[5])
dig_ns = 'dig @%(server_addr)s %(domain_name)s NS|grep "\sNS\s"' dig_ns = 'dig @%(server_addr)s %(domain_name)s NS|grep "\sNS\s"'
name_servers = run(dig_ns % context).stdout name_servers = run(dig_ns % context).stdout
# testdomain.org. 3600 IN NS ns1.orchestra.lan. # testdomain.org. 3600 IN NS ns1.orchestra.lan.
@ -95,7 +95,7 @@ class DomainTestMixin(object):
self.assertEqual('IN', ns[2]) self.assertEqual('IN', ns[2])
self.assertEqual('NS', ns[3]) self.assertEqual('NS', ns[3])
self.assertIn(ns[4], ns_records) self.assertIn(ns[4], ns_records)
dig_mx = 'dig @%(server_addr)s %(domain_name)s MX|grep "\sMX\s"' dig_mx = 'dig @%(server_addr)s %(domain_name)s MX|grep "\sMX\s"'
mail_servers = run(dig_mx % context).stdout mail_servers = run(dig_mx % context).stdout
for mx in mail_servers.splitlines(): for mx in mail_servers.splitlines():
@ -107,7 +107,7 @@ class DomainTestMixin(object):
self.assertEqual('MX', mx[3]) self.assertEqual('MX', mx[3])
self.assertIn(mx[4], ['10', '20']) self.assertIn(mx[4], ['10', '20'])
self.assertIn(mx[5], ['mail2.orchestra.lan.', 'mail.orchestra.lan.']) self.assertIn(mx[5], ['mail2.orchestra.lan.', 'mail.orchestra.lan.'])
def validate_delete(self, server_addr, domain_name): def validate_delete(self, server_addr, domain_name):
context = { context = {
'domain_name': domain_name, 'domain_name': domain_name,
@ -122,7 +122,7 @@ class DomainTestMixin(object):
self.assertNotEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) self.assertNotEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4])
hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER) hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER)
self.assertNotEqual(hostmaster, soa[5]) self.assertNotEqual(hostmaster, soa[5])
def validate_update(self, server_addr, domain_name): def validate_update(self, server_addr, domain_name):
context = { context = {
'domain_name': domain_name, 'domain_name': domain_name,
@ -138,7 +138,7 @@ class DomainTestMixin(object):
self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4])
hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER) hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER)
self.assertEqual(hostmaster, soa[5]) self.assertEqual(hostmaster, soa[5])
dig_ns = 'dig @%(server_addr)s %(domain_name)s NS |grep "\sNS\s"' dig_ns = 'dig @%(server_addr)s %(domain_name)s NS |grep "\sNS\s"'
name_servers = run(dig_ns % context).stdout name_servers = run(dig_ns % context).stdout
ns_records = ['ns1.%s.' % self.domain_name, 'ns2.%s.' % self.domain_name] ns_records = ['ns1.%s.' % self.domain_name, 'ns2.%s.' % self.domain_name]
@ -151,7 +151,7 @@ class DomainTestMixin(object):
self.assertEqual('IN', ns[2]) self.assertEqual('IN', ns[2])
self.assertEqual('NS', ns[3]) self.assertEqual('NS', ns[3])
self.assertIn(ns[4], ns_records) self.assertIn(ns[4], ns_records)
dig_mx = 'dig @%(server_addr)s %(domain_name)s MX | grep "\sMX\s"' dig_mx = 'dig @%(server_addr)s %(domain_name)s MX | grep "\sMX\s"'
mx = run(dig_mx % context).stdout.split() mx = run(dig_mx % context).stdout.split()
# testdomain.org. 3600 IN MX 10 orchestra.lan. # testdomain.org. 3600 IN MX 10 orchestra.lan.
@ -161,7 +161,7 @@ class DomainTestMixin(object):
self.assertEqual('MX', mx[3]) self.assertEqual('MX', mx[3])
self.assertIn(mx[4], ['30', '40']) self.assertIn(mx[4], ['30', '40'])
self.assertIn(mx[5], ['mail3.orchestra.lan.', 'mail4.orchestra.lan.']) self.assertIn(mx[5], ['mail3.orchestra.lan.', 'mail4.orchestra.lan.'])
def validate_www_update(self, server_addr, domain_name): def validate_www_update(self, server_addr, domain_name):
context = { context = {
'domain_name': domain_name, 'domain_name': domain_name,
@ -175,7 +175,7 @@ class DomainTestMixin(object):
self.assertEqual('IN', cname[2]) self.assertEqual('IN', cname[2])
self.assertEqual('CNAME', cname[3]) self.assertEqual('CNAME', cname[3])
self.assertEqual('external.server.org.', cname[4]) self.assertEqual('external.server.org.', cname[4])
def test_add(self): def test_add(self):
self.add(self.ns1_name, self.ns1_records) self.add(self.ns1_name, self.ns1_records)
self.add(self.ns2_name, self.ns2_records) self.add(self.ns2_name, self.ns2_records)
@ -184,7 +184,7 @@ class DomainTestMixin(object):
self.validate_add(self.MASTER_SERVER_ADDR, self.domain_name) self.validate_add(self.MASTER_SERVER_ADDR, self.domain_name)
time.sleep(1) time.sleep(1)
self.validate_add(self.SLAVE_SERVER_ADDR, self.domain_name) self.validate_add(self.SLAVE_SERVER_ADDR, self.domain_name)
def test_delete(self): def test_delete(self):
self.add(self.ns1_name, self.ns1_records) self.add(self.ns1_name, self.ns1_records)
self.add(self.ns2_name, self.ns2_records) self.add(self.ns2_name, self.ns2_records)
@ -193,7 +193,7 @@ class DomainTestMixin(object):
for name in [self.domain_name, self.ns1_name, self.ns2_name]: for name in [self.domain_name, self.ns1_name, self.ns2_name]:
self.validate_delete(self.MASTER_SERVER_ADDR, name) self.validate_delete(self.MASTER_SERVER_ADDR, name)
self.validate_delete(self.SLAVE_SERVER_ADDR, name) self.validate_delete(self.SLAVE_SERVER_ADDR, name)
def test_update(self): def test_update(self):
self.add(self.ns1_name, self.ns1_records) self.add(self.ns1_name, self.ns1_records)
self.add(self.ns2_name, self.ns2_records) self.add(self.ns2_name, self.ns2_records)
@ -209,7 +209,7 @@ class DomainTestMixin(object):
self.validate_www_update(self.MASTER_SERVER_ADDR, self.domain_name) self.validate_www_update(self.MASTER_SERVER_ADDR, self.domain_name)
time.sleep(5) time.sleep(5)
self.validate_www_update(self.SLAVE_SERVER_ADDR, self.domain_name) self.validate_www_update(self.SLAVE_SERVER_ADDR, self.domain_name)
def test_add_add_delete_delete(self): def test_add_add_delete_delete(self):
self.add(self.ns1_name, self.ns1_records) self.add(self.ns1_name, self.ns1_records)
self.add(self.ns2_name, self.ns2_records) self.add(self.ns2_name, self.ns2_records)
@ -221,7 +221,7 @@ class DomainTestMixin(object):
self.delete(self.django_domain_name) self.delete(self.django_domain_name)
self.validate_delete(self.MASTER_SERVER_ADDR, self.django_domain_name) self.validate_delete(self.MASTER_SERVER_ADDR, self.django_domain_name)
self.validate_delete(self.SLAVE_SERVER_ADDR, self.django_domain_name) self.validate_delete(self.SLAVE_SERVER_ADDR, self.django_domain_name)
def test_bad_creation(self): def test_bad_creation(self):
self.assertRaises((self.rest.ResponseStatusError, AssertionError), self.assertRaises((self.rest.ResponseStatusError, AssertionError),
self.add, self.domain_name, self.domain_records) self.add, self.domain_name, self.domain_records)
@ -232,7 +232,7 @@ class AdminDomainMixin(DomainTestMixin):
super(AdminDomainMixin, self).setUp() super(AdminDomainMixin, self).setUp()
self.add_route() self.add_route()
self.admin_login() self.admin_login()
def _add_records(self, records): def _add_records(self, records):
self.selenium.find_element_by_link_text('Add another Record').click() self.selenium.find_element_by_link_text('Add another Record').click()
for i, record in zip(range(0, len(records)), records): for i, record in zip(range(0, len(records)), records):
@ -244,29 +244,29 @@ class AdminDomainMixin(DomainTestMixin):
value_input.clear() value_input.clear()
value_input.send_keys(value) value_input.send_keys(value)
return value_input return value_input
@snapshot_on_error @snapshot_on_error
def add(self, domain_name, records): def add(self, domain_name, records):
add = reverse('admin:domains_domain_add') add = reverse('admin:domains_domain_add')
url = self.live_server_url + add url = self.live_server_url + add
self.selenium.get(url) self.selenium.get(url)
name = self.selenium.find_element_by_id('id_name') name = self.selenium.find_element_by_id('id_name')
name.send_keys(domain_name) name.send_keys(domain_name)
account_input = self.selenium.find_element_by_id('id_account') account_input = self.selenium.find_element_by_id('id_account')
account_select = Select(account_input) account_select = Select(account_input)
account_select.select_by_value(str(self.account.pk)) account_select.select_by_value(str(self.account.pk))
value_input = self._add_records(records) value_input = self._add_records(records)
value_input.submit() value_input.submit()
self.assertNotEqual(url, self.selenium.current_url) self.assertNotEqual(url, self.selenium.current_url)
@snapshot_on_error @snapshot_on_error
def delete(self, domain_name): def delete(self, domain_name):
domain = Domain.objects.get(name=domain_name) domain = Domain.objects.get(name=domain_name)
self.admin_delete(domain) self.admin_delete(domain)
@snapshot_on_error @snapshot_on_error
def update(self, domain_name, records): def update(self, domain_name, records):
domain = Domain.objects.get(name=domain_name) domain = Domain.objects.get(name=domain_name)
@ -283,18 +283,18 @@ class RESTDomainMixin(DomainTestMixin):
super(RESTDomainMixin, self).setUp() super(RESTDomainMixin, self).setUp()
self.rest_login() self.rest_login()
self.add_route() self.add_route()
@save_response_on_error @save_response_on_error
def add(self, domain_name, records): def add(self, domain_name, records):
records = [ dict(type=type, value=value) for type,value in records ] records = [ dict(type=type, value=value) for type,value in records ]
self.rest.domains.create(name=domain_name, records=records) self.rest.domains.create(name=domain_name, records=records)
@save_response_on_error @save_response_on_error
def delete(self, domain_name): def delete(self, domain_name):
domain = Domain.objects.get(name=domain_name) domain = Domain.objects.get(name=domain_name)
domain = self.rest.domains.retrieve(id=domain.pk) domain = self.rest.domains.retrieve(id=domain.pk)
domain.delete() domain.delete()
@save_response_on_error @save_response_on_error
def update(self, domain_name, records): def update(self, domain_name, records):
records = [ dict(type=type, value=value) for type,value in records ] records = [ dict(type=type, value=value) for type,value in records ]
@ -307,7 +307,7 @@ class Bind9BackendMixin(object):
DEPENDENCIES = ( DEPENDENCIES = (
'orchestra.contrib.orchestration', 'orchestra.contrib.orchestration',
) )
def add_route(self): def add_route(self):
master = Server.objects.create(name=self.MASTER_SERVER, address=self.MASTER_SERVER_ADDR) master = Server.objects.create(name=self.MASTER_SERVER, address=self.MASTER_SERVER_ADDR)
backend = backends.Bind9MasterDomainController.get_name() backend = backends.Bind9MasterDomainController.get_name()

View File

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.contrib.admin.utils import unquote from django.contrib.admin.utils import unquote
@ -30,10 +30,10 @@ class LogEntryAdmin(admin.ModelAdmin):
actions = None actions = None
list_select_related = ('user', 'content_type') list_select_related = ('user', 'content_type')
list_display_links = None list_display_links = None
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"))
def display_message(self, log): def display_message(self, log):
edit = '<a href="%(url)s"><img src="%(img)s"></img></a>' % { edit = '<a href="%(url)s"><img src="%(img)s"></img></a>' % {
'url': reverse('admin:admin_logentry_change', args=(log.pk,)), 'url': reverse('admin:admin_logentry_change', args=(log.pk,)),
@ -58,7 +58,7 @@ class LogEntryAdmin(admin.ModelAdmin):
display_message.short_description = _("Message") display_message.short_description = _("Message")
display_message.admin_order_field = 'action_flag' display_message.admin_order_field = 'action_flag'
display_message.allow_tags = True display_message.allow_tags = True
def display_action(self, log): def display_action(self, log):
if log.is_addition(): if log.is_addition():
return _("Added") return _("Added")
@ -67,7 +67,7 @@ class LogEntryAdmin(admin.ModelAdmin):
return _("Deleted") return _("Deleted")
display_action.short_description = _("Action") display_action.short_description = _("Action")
display_action.admin_order_field = 'action_flag' display_action.admin_order_field = 'action_flag'
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)
@ -79,7 +79,7 @@ class LogEntryAdmin(admin.ModelAdmin):
content_object_link.short_description = _("Content object") content_object_link.short_description = _("Content object")
content_object_link.admin_order_field = 'object_repr' content_object_link.admin_order_field = 'object_repr'
content_object_link.allow_tags = True content_object_link.allow_tags = True
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 """
if not add and 'edit' in request.GET.urlencode(): if not add and 'edit' in request.GET.urlencode():
@ -89,14 +89,14 @@ class LogEntryAdmin(admin.ModelAdmin):
}) })
return super(LogEntryAdmin, self).render_change_form( return super(LogEntryAdmin, self).render_change_form(
request, context, add, change, form_url, obj) request, context, add, change, form_url, obj)
def response_change(self, request, obj): def response_change(self, request, obj):
""" save and continue preserve edit query string """ """ save and continue preserve edit query string """
response = super(LogEntryAdmin, self).response_change(request, obj) response = super(LogEntryAdmin, self).response_change(request, obj)
if 'edit' in request.GET.urlencode() and 'edit' not in response.url: if 'edit' in request.GET.urlencode() and 'edit' not in response.url:
return HttpResponseRedirect(response.url + '?edit=True') return HttpResponseRedirect(response.url + '?edit=True')
return response return response
def response_post_save_change(self, request, obj): def response_post_save_change(self, request, obj):
""" save redirect to object history """ """ save redirect to object history """
if 'edit' in request.GET.urlencode(): if 'edit' in request.GET.urlencode():
@ -109,19 +109,19 @@ class LogEntryAdmin(admin.ModelAdmin):
}, post_url) }, post_url)
return HttpResponseRedirect(post_url) return HttpResponseRedirect(post_url)
return super(LogEntryAdmin, self).response_post_save_change(request, obj) return super(LogEntryAdmin, self).response_post_save_change(request, obj)
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
def has_delete_permission(self, *args, **kwargs): def has_delete_permission(self, *args, **kwargs):
return False return False
def log_addition(self, *args, **kwargs): def log_addition(self, *args, **kwargs):
pass pass
def log_change(self, *args, **kwargs): def log_change(self, *args, **kwargs):
pass pass
def log_deletion(self, *args, **kwargs): def log_deletion(self, *args, **kwargs):
pass pass

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@ -21,14 +21,14 @@ from .helpers import get_ticket_changes, markdown_formated_changes, filter_actio
from .models import Ticket, Queue, Message from .models import Ticket, Queue, Message
PRIORITY_COLORS = { PRIORITY_COLORS = {
Ticket.HIGH: 'red', Ticket.HIGH: 'red',
Ticket.MEDIUM: 'darkorange', Ticket.MEDIUM: 'darkorange',
Ticket.LOW: 'green', Ticket.LOW: 'green',
} }
STATE_COLORS = { STATE_COLORS = {
Ticket.NEW: 'grey', Ticket.NEW: 'grey',
Ticket.IN_PROGRESS: 'darkorange', Ticket.IN_PROGRESS: 'darkorange',
Ticket.FEEDBACK: 'purple', Ticket.FEEDBACK: 'purple',
@ -44,12 +44,12 @@ class MessageReadOnlyInline(admin.TabularInline):
can_delete = False can_delete = False
fields = ('content_html',) fields = ('content_html',)
readonly_fields = ('content_html',) readonly_fields = ('content_html',)
class Media: class Media:
css = { css = {
'all': ('orchestra/css/hide-inline-id.css',) 'all': ('orchestra/css/hide-inline-id.css',)
} }
def content_html(self, msg): def content_html(self, msg):
context = { context = {
'number': msg.number, 'number': msg.number,
@ -64,10 +64,10 @@ class MessageReadOnlyInline(admin.TabularInline):
return header + content return header + content
content_html.short_description = _("Content") content_html.short_description = _("Content")
content_html.allow_tags = True content_html.allow_tags = True
def has_add_permission(self, request): def has_add_permission(self, request):
return False return False
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
return False return False
@ -79,12 +79,12 @@ class MessageInline(admin.TabularInline):
form = MessageInlineForm form = MessageInlineForm
can_delete = False can_delete = False
fields = ('content',) fields = ('content',)
def get_formset(self, request, obj=None, **kwargs): def get_formset(self, request, obj=None, **kwargs):
""" hook request.user on the inline form """ """ hook request.user on the inline form """
self.form.user = request.user self.form.user = request.user
return super(MessageInline, self).get_formset(request, obj, **kwargs) return super(MessageInline, self).get_formset(request, obj, **kwargs)
def get_queryset(self, request): def get_queryset(self, request):
""" Don't show any message """ """ Don't show any message """
qs = super(MessageInline, self).get_queryset(request) qs = super(MessageInline, self).get_queryset(request)
@ -103,14 +103,14 @@ class TicketInline(admin.TabularInline):
model = Ticket model = Ticket
extra = 0 extra = 0
max_num = 0 max_num = 0
creator_link = admin_link('creator') creator_link = admin_link('creator')
owner_link = admin_link('owner') owner_link = admin_link('owner')
created = admin_link('created_at') created = admin_link('created_at')
updated = admin_link('updated_at') updated = admin_link('updated_at')
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)
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 = '#' ticket_id.short_description = '#'
@ -176,7 +176,7 @@ class TicketAdmin(ExtendedModelAdmin):
}), }),
) )
list_select_related = ('queue', 'owner', 'creator') list_select_related = ('queue', 'owner', 'creator')
class Media: class Media:
css = { css = {
'all': ('issues/css/ticket-admin.css',) 'all': ('issues/css/ticket-admin.css',)
@ -184,14 +184,14 @@ class TicketAdmin(ExtendedModelAdmin):
js = ( js = (
'issues/js/ticket-admin.js', 'issues/js/ticket-admin.js',
) )
display_creator = admin_link('creator') display_creator = admin_link('creator')
display_queue = admin_link('queue') display_queue = admin_link('queue')
display_owner = admin_link('owner') display_owner = admin_link('owner')
updated = admin_date('updated_at') updated = admin_date('updated_at')
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)
def display_summary(self, ticket): def display_summary(self, ticket):
context = { context = {
'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name, 'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name,
@ -208,7 +208,7 @@ class TicketAdmin(ExtendedModelAdmin):
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' display_summary.short_description = 'Summary'
display_summary.allow_tags = True display_summary.allow_tags = True
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):
@ -217,7 +217,7 @@ class TicketAdmin(ExtendedModelAdmin):
unbold_id.allow_tags = True unbold_id.allow_tags = True
unbold_id.short_description = "#" unbold_id.short_description = "#"
unbold_id.admin_order_field = 'id' unbold_id.admin_order_field = 'id'
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):
@ -226,31 +226,31 @@ class TicketAdmin(ExtendedModelAdmin):
bold_subject.allow_tags = True bold_subject.allow_tags = True
bold_subject.short_description = _("Subject") bold_subject.short_description = _("Subject")
bold_subject.admin_order_field = '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 """
if db_field.name == 'subject': if db_field.name == 'subject':
kwargs['widget'] = forms.TextInput(attrs={'size':'120'}) kwargs['widget'] = forms.TextInput(attrs={'size':'120'})
return super(TicketAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(TicketAdmin, self).formfield_for_dbfield(db_field, **kwargs)
def save_model(self, request, obj, *args, **kwargs): def save_model(self, request, obj, *args, **kwargs):
""" Define creator for new tickets """ """ Define creator for new tickets """
if not obj.pk: if not obj.pk:
obj.creator = request.user obj.creator = request.user
super(TicketAdmin, self).save_model(request, obj, *args, **kwargs) super(TicketAdmin, self).save_model(request, obj, *args, **kwargs)
obj.mark_as_read_by(request.user) obj.mark_as_read_by(request.user)
def get_urls(self): def get_urls(self):
""" add markdown preview url """ """ add markdown preview url """
return [ return [
url(r'^preview/$', url(r'^preview/$',
wrap_admin_view(self, self.message_preview_view)) wrap_admin_view(self, self.message_preview_view))
] + super(TicketAdmin, self).get_urls() ] + super(TicketAdmin, self).get_urls()
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url='', extra_context=None):
""" Do not sow message inlines """ """ Do not sow message inlines """
return super(TicketAdmin, self).add_view(request, form_url, extra_context) return super(TicketAdmin, self).add_view(request, form_url, extra_context)
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url='', extra_context=None):
""" Change view actions based on ticket state """ """ Change view actions based on ticket state """
ticket = get_object_or_404(Ticket, pk=object_id) ticket = get_object_or_404(Ticket, pk=object_id)
@ -269,12 +269,12 @@ class TicketAdmin(ExtendedModelAdmin):
context.update(extra_context or {}) context.update(extra_context or {})
return super(TicketAdmin, self).change_view(request, object_id, form_url=form_url, return super(TicketAdmin, self).change_view(request, object_id, form_url=form_url,
extra_context=context) extra_context=context)
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
# Hook user for bold_subject # Hook user for bold_subject
self.user = request.user self.user = request.user
return super(TicketAdmin,self).changelist_view(request, extra_context=extra_context) return super(TicketAdmin,self).changelist_view(request, extra_context=extra_context)
def message_preview_view(self, request): def message_preview_view(self, request):
""" markdown preview render via ajax """ """ markdown preview render via ajax """
data = request.POST.get("data") data = request.POST.get("data")
@ -287,12 +287,12 @@ class QueueAdmin(admin.ModelAdmin):
actions = (set_default_queue,) actions = (set_default_queue,)
inlines = (TicketInline,) inlines = (TicketInline,)
ordering = ('name',) ordering = ('name',)
class Media: class Media:
css = { css = {
'all': ('orchestra/css/hide-inline-id.css',) 'all': ('orchestra/css/hide-inline-id.css',)
} }
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')
@ -301,7 +301,7 @@ class QueueAdmin(admin.ModelAdmin):
num_tickets.short_description = _("Tickets") num_tickets.short_description = _("Tickets")
num_tickets.admin_order_field = 'tickets__count' num_tickets.admin_order_field = 'tickets__count'
num_tickets.allow_tags = True num_tickets.allow_tags = True
def get_list_display(self, request): def get_list_display(self, request):
""" show notifications """ """ show notifications """
list_display = list(self.list_display) list_display = list(self.list_display)
@ -312,7 +312,7 @@ class QueueAdmin(admin.ModelAdmin):
display_notify.boolean = True display_notify.boolean = True
list_display.append(display_notify) list_display.append(display_notify)
return list_display return list_display
def get_queryset(self, request): def get_queryset(self, request):
qs = super(QueueAdmin, self).get_queryset(request) qs = super(QueueAdmin, self).get_queryset(request)
qs = qs.annotate(models.Count('tickets')) qs = qs.annotate(models.Count('tickets'))

View File

@ -7,7 +7,7 @@ from email.mime.text import MIMEText
import requests import requests
from django.conf import settings as djsettings from django.conf import settings as djsettings
from django.core.management.base import CommandError from django.core.management.base import CommandError
from django.core.urlresolvers import reverse from django.urls import reverse
from orchestra.admin.utils import change_url from orchestra.admin.utils import change_url
from orchestra.contrib.domains.models import Domain from orchestra.contrib.domains.models import Domain
from orchestra.contrib.orchestration.models import Route, Server from orchestra.contrib.orchestration.models import Route, Server

View File

@ -3,7 +3,7 @@ from urllib.parse import parse_qs
from django import forms from django import forms
from django.contrib import admin, messages from django.contrib import admin, messages
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db.models import F, Count, Value as V from django.db.models import F, Count, Value as V
from django.db.models.functions import Concat from django.db.models.functions import Concat
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -28,7 +28,7 @@ from .widgets import OpenCustomFilteringOnSelect
class AutoresponseInline(admin.StackedInline): class AutoresponseInline(admin.StackedInline):
model = Autoresponse model = Autoresponse
verbose_name_plural = _("autoresponse") verbose_name_plural = _("autoresponse")
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'subject': if db_field.name == 'subject':
kwargs['widget'] = forms.TextInput(attrs={'size':'118'}) kwargs['widget'] = forms.TextInput(attrs={'size':'118'})
@ -76,12 +76,12 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
form = MailboxChangeForm form = MailboxChangeForm
list_prefetch_related = ('addresses__domain',) list_prefetch_related = ('addresses__domain',)
actions = (disable, enable, list_accounts) actions = (disable, enable, list_accounts)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MailboxAdmin, self).__init__(*args, **kwargs) super(MailboxAdmin, self).__init__(*args, **kwargs)
if settings.MAILBOXES_LOCAL_DOMAIN: if settings.MAILBOXES_LOCAL_DOMAIN:
type(self).actions = self.actions + (SendMailboxEmail(),) type(self).actions = self.actions + (SendMailboxEmail(),)
def display_addresses(self, mailbox): def display_addresses(self, mailbox):
# Get from forwards # Get from forwards
cache = caches.get_request_cache() cache = caches.get_request_cache()
@ -111,7 +111,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
return '<br>'.join(addresses+forwards) return '<br>'.join(addresses+forwards)
display_addresses.short_description = _("Addresses") display_addresses.short_description = _("Addresses")
display_addresses.allow_tags = True display_addresses.allow_tags = True
def display_forwards(self, mailbox): def display_forwards(self, mailbox):
forwards = [] forwards = []
for addr in mailbox.get_forwards(): for addr in mailbox.get_forwards():
@ -120,19 +120,19 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
return '<br>'.join(forwards) return '<br>'.join(forwards)
display_forwards.short_description = _("Forward from") display_forwards.short_description = _("Forward from")
display_forwards.allow_tags = True display_forwards.allow_tags = True
def display_filtering(self, mailbox): def display_filtering(self, mailbox):
""" becacuse of allow_tags = True """ """ becacuse of allow_tags = True """
return mailbox.get_filtering_display() return mailbox.get_filtering_display()
display_filtering.short_description = _("Filtering") display_filtering.short_description = _("Filtering")
display_filtering.admin_order_field = 'filtering' display_filtering.admin_order_field = 'filtering'
display_filtering.allow_tags = True display_filtering.allow_tags = True
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':
kwargs['widget'] = OpenCustomFilteringOnSelect() kwargs['widget'] = OpenCustomFilteringOnSelect()
return super(MailboxAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(MailboxAdmin, self).formfield_for_dbfield(db_field, **kwargs)
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
fieldsets = super(MailboxAdmin, self).get_fieldsets(request, obj) fieldsets = super(MailboxAdmin, self).get_fieldsets(request, obj)
if obj and obj.filtering == obj.CUSTOM: if obj and obj.filtering == obj.CUSTOM:
@ -144,31 +144,31 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
fieldsets = list(copy.deepcopy(fieldsets)) fieldsets = list(copy.deepcopy(fieldsets))
fieldsets.pop(-1) fieldsets.pop(-1)
return fieldsets return fieldsets
def get_form(self, *args, **kwargs): def get_form(self, *args, **kwargs):
form = super(MailboxAdmin, self).get_form(*args, **kwargs) form = super(MailboxAdmin, self).get_form(*args, **kwargs)
form.modeladmin = self form.modeladmin = self
return form return form
def get_search_results(self, request, queryset, search_term): def get_search_results(self, request, queryset, search_term):
# Remove local domain from the search term if present (implicit local addreç) # Remove local domain from the search term if present (implicit local addreç)
search_term = search_term.replace('@'+settings.MAILBOXES_LOCAL_DOMAIN, '') search_term = search_term.replace('@'+settings.MAILBOXES_LOCAL_DOMAIN, '')
# Split address name from domain in order to support address searching # Split address name from domain in order to support address searching
search_term = search_term.replace('@', ' ') search_term = search_term.replace('@', ' ')
return super(MailboxAdmin, self).get_search_results(request, queryset, search_term) return super(MailboxAdmin, self).get_search_results(request, queryset, search_term)
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):
if not add: if not add:
self.check_unrelated_address(request, obj) self.check_unrelated_address(request, obj)
self.check_matching_address(request, obj) self.check_matching_address(request, obj)
return super(MailboxAdmin, self).render_change_form( return super(MailboxAdmin, self).render_change_form(
request, context, add, change, form_url, obj) request, context, add, change, form_url, obj)
def log_addition(self, request, object, *args, **kwargs): def log_addition(self, request, object, *args, **kwargs):
self.check_unrelated_address(request, object) self.check_unrelated_address(request, object)
self.check_matching_address(request, object) self.check_matching_address(request, object)
return super(MailboxAdmin, self).log_addition(request, object, *args, **kwargs) return super(MailboxAdmin, self).log_addition(request, object, *args, **kwargs)
def check_matching_address(self, request, obj): def check_matching_address(self, request, obj):
local_domain = settings.MAILBOXES_LOCAL_DOMAIN local_domain = settings.MAILBOXES_LOCAL_DOMAIN
if obj.name and local_domain: if obj.name and local_domain:
@ -183,7 +183,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
"selecting it makes sense.") % (obj, addr) "selecting it makes sense.") % (obj, addr)
if msg not in (m.message for m in messages.get_messages(request)): if msg not in (m.message for m in messages.get_messages(request)):
self.message_user(request, msg, level=messages.WARNING) self.message_user(request, msg, level=messages.WARNING)
def check_unrelated_address(self, request, obj): def check_unrelated_address(self, request, obj):
# Check if there exists an unrelated local Address for this mbox # Check if there exists an unrelated local Address for this mbox
local_domain = settings.MAILBOXES_LOCAL_DOMAIN local_domain = settings.MAILBOXES_LOCAL_DOMAIN
@ -204,7 +204,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
# Prevent duplication (add_view+continue) # Prevent duplication (add_view+continue)
if msg not in (m.message for m in messages.get_messages(request)): if msg not in (m.message for m in messages.get_messages(request)):
self.message_user(request, msg, level=messages.WARNING) self.message_user(request, msg, level=messages.WARNING)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
""" save hacky mailbox.addresses and local domain clashing """ """ save hacky mailbox.addresses and local domain clashing """
if obj.filtering != obj.CUSTOM: if obj.filtering != obj.CUSTOM:
@ -237,20 +237,20 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
filter_horizontal = ['mailboxes'] filter_horizontal = ['mailboxes']
form = AddressForm form = AddressForm
list_prefetch_related = ('mailboxes', 'domain') list_prefetch_related = ('mailboxes', 'domain')
domain_link = admin_link('domain', order='domain__name') domain_link = admin_link('domain', order='domain__name')
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.short_description = _("Email")
display_email.admin_order_field = 'computed_email' display_email.admin_order_field = 'computed_email'
def email_link(self, address): def email_link(self, address):
link = self.domain_link(address) link = self.domain_link(address)
return "%s@%s" % (address.name, link) return "%s@%s" % (address.name, link)
email_link.short_description = _("Email") email_link.short_description = _("Email")
email_link.allow_tags = True email_link.allow_tags = True
def display_mailboxes(self, address): def display_mailboxes(self, address):
boxes = [] boxes = []
for mailbox in address.mailboxes.all(): for mailbox in address.mailboxes.all():
@ -260,7 +260,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
display_mailboxes.short_description = _("Mailboxes") display_mailboxes.short_description = _("Mailboxes")
display_mailboxes.allow_tags = True display_mailboxes.allow_tags = True
display_mailboxes.admin_order_field = 'mailboxes__count' display_mailboxes.admin_order_field = 'mailboxes__count'
def display_all_mailboxes(self, address): def display_all_mailboxes(self, address):
boxes = [] boxes = []
for mailbox in address.get_mailboxes(): for mailbox in address.get_mailboxes():
@ -269,7 +269,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
return '<br>'.join(boxes) return '<br>'.join(boxes)
display_all_mailboxes.short_description = _("Mailboxes links") display_all_mailboxes.short_description = _("Mailboxes links")
display_all_mailboxes.allow_tags = True display_all_mailboxes.allow_tags = True
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()}
values = [] values = []
@ -283,12 +283,12 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
display_forward.short_description = _("Forward") display_forward.short_description = _("Forward")
display_forward.allow_tags = True display_forward.allow_tags = True
display_forward.admin_order_field = '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':
kwargs['widget'] = forms.TextInput(attrs={'size':'118'}) kwargs['widget'] = forms.TextInput(attrs={'size':'118'})
return super(AddressAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(AddressAdmin, self).formfield_for_dbfield(db_field, **kwargs)
def get_fields(self, request, obj=None): def get_fields(self, request, obj=None):
""" Remove mailboxes field when creating address from a popup i.e. from mailbox add form """ """ Remove mailboxes field when creating address from a popup i.e. from mailbox add form """
fields = super(AddressAdmin, self).get_fields(request, obj) fields = super(AddressAdmin, self).get_fields(request, obj)
@ -297,22 +297,22 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
fields = list(fields) fields = list(fields)
fields.remove('mailboxes') fields.remove('mailboxes')
return fields return fields
def get_queryset(self, request): def get_queryset(self, request):
qs = super(AddressAdmin, self).get_queryset(request) qs = super(AddressAdmin, self).get_queryset(request)
qs = qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name'))) qs = qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name')))
return qs.annotate(Count('mailboxes')) return qs.annotate(Count('mailboxes'))
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):
if not add: if not add:
self.check_matching_mailbox(request, obj) self.check_matching_mailbox(request, obj)
return super(AddressAdmin, self).render_change_form( return super(AddressAdmin, self).render_change_form(
request, context, add, change, form_url, obj) request, context, add, change, form_url, obj)
def log_addition(self, request, object, *args, **kwargs): def log_addition(self, request, object, *args, **kwargs):
self.check_matching_mailbox(request, object) self.check_matching_mailbox(request, object)
return super(AddressAdmin, self).log_addition(request, object, *args, **kwargs) return super(AddressAdmin, self).log_addition(request, object, *args, **kwargs)
def check_matching_mailbox(self, request, obj): def check_matching_mailbox(self, request, obj):
# Check if new addresse matches with a mbox because of having a local domain # Check if new addresse matches with a mbox because of having a local domain
if obj.name and obj.domain and obj.domain.name == settings.MAILBOXES_LOCAL_DOMAIN: if obj.name and obj.domain and obj.domain.name == settings.MAILBOXES_LOCAL_DOMAIN:

View File

@ -11,7 +11,7 @@ from django.apps import apps
from django.conf import settings as djsettings from django.conf import settings as djsettings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.management.base import CommandError from django.core.management.base import CommandError
from django.core.urlresolvers import reverse from django.urls import reverse
from selenium.webdriver.support.select import Select from selenium.webdriver.support.select import Select
from orchestra.contrib.orchestration.models import Server, Route from orchestra.contrib.orchestration.models import Server, Route

View File

@ -1,4 +1,4 @@
from django.core.urlresolvers import reverse from django.urls import reverse
from django.shortcuts import redirect from django.shortcuts import redirect

View File

@ -3,7 +3,7 @@ import email
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db.models import Count from django.db.models import Count
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -52,11 +52,11 @@ class MessageAdmin(ExtendedModelAdmin):
) )
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
change_view_actions = (last,) change_view_actions = (last,)
colored_state = admin_colored('state', colors=COLORS) colored_state = admin_colored('state', colors=COLORS)
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')
def display_subject(self, instance): def display_subject(self, instance):
subject = instance.subject subject = instance.subject
if len(subject) > 64: if len(subject) > 64:
@ -65,7 +65,7 @@ class MessageAdmin(ExtendedModelAdmin):
display_subject.short_description = _("Subject") display_subject.short_description = _("Subject")
display_subject.admin_order_field = 'subject' display_subject.admin_order_field = 'subject'
display_subject.allow_tags = True display_subject.allow_tags = True
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:
@ -78,7 +78,7 @@ class MessageAdmin(ExtendedModelAdmin):
display_retries.short_description = _("Retries") display_retries.short_description = _("Retries")
display_retries.admin_order_field = 'retries' display_retries.admin_order_field = 'retries'
display_retries.allow_tags = True display_retries.allow_tags = True
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()
@ -102,19 +102,19 @@ class MessageAdmin(ExtendedModelAdmin):
return payload return payload
display_content.short_description = _("Content") display_content.short_description = _("Content")
display_content.allow_tags = True display_content.allow_tags = True
def display_full_subject(self, instance): def display_full_subject(self, instance):
return instance.subject return instance.subject
display_full_subject.short_description = _("Subject") display_full_subject.short_description = _("Subject")
def display_from(self, instance): def display_from(self, instance):
return instance.from_address return instance.from_address
display_from.short_description = _("From") display_from.short_description = _("From")
def display_to(self, instance): def display_to(self, instance):
return instance.to_address return instance.to_address
display_to.short_description = _("To") display_to.short_description = _("To")
def get_urls(self): def get_urls(self):
from django.conf.urls import url from django.conf.urls import url
urls = super().get_urls() urls = super().get_urls()
@ -125,16 +125,16 @@ class MessageAdmin(ExtendedModelAdmin):
name='%s_%s_send_pending' % info) name='%s_%s_send_pending' % info)
) )
return urls return urls
def get_queryset(self, request): def get_queryset(self, request):
qs = super().get_queryset(request) qs = super().get_queryset(request)
return qs.annotate(Count('logs')).defer('content') return qs.annotate(Count('logs')).defer('content')
def send_pending_view(self, request): def send_pending_view(self, request):
task(send_pending).apply_async() task(send_pending).apply_async()
self.message_user(request, _("Pending messages are being sent on the background.")) self.message_user(request, _("Pending messages are being sent on the background."))
return redirect('..') return redirect('..')
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'subject': if db_field.name == 'subject':
kwargs['widget'] = forms.TextInput(attrs={'size':'100'}) kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
@ -148,7 +148,7 @@ class SMTPLogAdmin(admin.ModelAdmin):
list_filter = ('result',) list_filter = ('result',)
fields = ('message_link', 'colored_result', 'date_delta', 'log_message') fields = ('message_link', 'colored_result', 'date_delta', 'log_message')
readonly_fields = fields readonly_fields = fields
message_link = admin_link('message') message_link = admin_link('message')
colored_result = admin_colored('result', colors=COLORS, bold=False) colored_result = admin_colored('result', colors=COLORS, bold=False)
date_delta = admin_date('date') date_delta = admin_date('date')

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -36,19 +36,19 @@ class MiscServiceAdmin(ExtendedModelAdmin):
prepopulated_fields = {'name': ('verbose_name',)} prepopulated_fields = {'name': ('verbose_name',)}
change_readonly_fields = ('name',) change_readonly_fields = ('name',)
actions = (disable, enable) actions = (disable, enable)
def display_name(self, misc): def display_name(self, misc):
return '<span title="%s">%s</span>' % (misc.description, misc.name) return '<span title="%s">%s</span>' % (misc.description, misc.name)
display_name.short_description = _("name") display_name.short_description = _("name")
display_name.allow_tags = True display_name.allow_tags = True
display_name.admin_order_field = 'name' display_name.admin_order_field = 'name'
def display_verbose_name(self, misc): def display_verbose_name(self, misc):
return '<span title="%s">%s</span>' % (misc.description, misc.verbose_name) return '<span title="%s">%s</span>' % (misc.description, misc.verbose_name)
display_verbose_name.short_description = _("verbose name") display_verbose_name.short_description = _("verbose name")
display_verbose_name.allow_tags = True display_verbose_name.allow_tags = True
display_verbose_name.admin_order_field = 'verbose_name' display_verbose_name.admin_order_field = 'verbose_name'
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
@ -57,11 +57,11 @@ class MiscServiceAdmin(ExtendedModelAdmin):
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.short_description = _("Instances")
num_instances.admin_order_field = 'instances__count' 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)
return qs.annotate(models.Count('instances', distinct=True)) return qs.annotate(models.Count('instances', distinct=True))
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 """
if db_field.name == 'description': if db_field.name == 'description':
@ -83,21 +83,21 @@ class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedMode
actions = (disable, enable) actions = (disable, enable)
plugin_field = 'service' plugin_field = 'service'
plugin = MiscServicePlugin plugin = MiscServicePlugin
service_link = admin_link('service') service_link = admin_link('service')
def dispaly_active(self, instance): def dispaly_active(self, instance):
return instance.active return instance.active
dispaly_active.short_description = _("Active") dispaly_active.short_description = _("Active")
dispaly_active.boolean = True dispaly_active.boolean = True
dispaly_active.admin_order_field = 'is_active' 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:
return self.plugin.get(self.plugin_value).related_instance return self.plugin.get(self.plugin_value).related_instance
else: else:
return obj.service return obj.service
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
fieldsets = super().get_fieldsets(request, obj) fieldsets = super().get_fieldsets(request, obj)
fields = list(fieldsets[0][1]['fields']) fields = list(fieldsets[0][1]['fields'])
@ -110,7 +110,7 @@ class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedMode
fields.insert(2, 'identifier') fields.insert(2, 'identifier')
fieldsets[0][1]['fields'] = fields fieldsets[0][1]['fields'] = fields
return fieldsets return fieldsets
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
if obj: if obj:
plugin = self.plugin.get(obj.service.name)() plugin = self.plugin.get(obj.service.name)()
@ -127,16 +127,16 @@ class MiscellaneousAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedMode
validator = import_class(validator_path) validator = import_class(validator_path)
validator(identifier) validator(identifier)
return identifier return identifier
form.clean_identifier = clean_identifier form.clean_identifier = clean_identifier
return form return form
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 """
if db_field.name == 'description': if db_field.name == 'description':
kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4}) kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4})
return super(MiscellaneousAdmin, self).formfield_for_dbfield(db_field, **kwargs) return super(MiscellaneousAdmin, self).formfield_for_dbfield(db_field, **kwargs)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
if not change: if not change:
plugin = self.plugin plugin = self.plugin

View File

@ -2,7 +2,7 @@ import textwrap
from django.contrib import messages from django.contrib import messages
from django.core.mail import mail_admins from django.core.mail import mail_admins
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _

View File

@ -1,7 +1,7 @@
from threading import local from threading import local
from django.contrib.admin.models import LogEntry from django.contrib.admin.models import LogEntry
from django.core.urlresolvers import resolve from django.urls import resolve
from django.db import transaction from django.db import transaction
from django.db.models.signals import pre_delete, post_save, m2m_changed from django.db.models.signals import pre_delete, post_save, m2m_changed
from django.dispatch import receiver from django.dispatch import receiver
@ -39,12 +39,12 @@ class OperationsMiddleware(object):
""" """
Stores all the operations derived from save and delete signals and executes them Stores all the operations derived from save and delete signals and executes them
at the end of the request/response cycle at the end of the request/response cycle
It also works as a transaction middleware, making requets to run within an atomic block. It also works as a transaction middleware, making requets to run within an atomic block.
""" """
# Thread local is used because request object is not available on model signals # Thread local is used because request object is not available on model signals
thread_locals = local() thread_locals = local()
@classmethod @classmethod
def get_pending_operations(cls): def get_pending_operations(cls):
# Check if an error poped up before OperationsMiddleware.process_request() # Check if an error poped up before OperationsMiddleware.process_request()
@ -54,7 +54,7 @@ class OperationsMiddleware(object):
request.pending_operations = OrderedSet() request.pending_operations = OrderedSet()
return request.pending_operations return request.pending_operations
return set() return set()
@classmethod @classmethod
def get_route_cache(cls): def get_route_cache(cls):
""" chache the routes to save sql queries """ """ chache the routes to save sql queries """
@ -64,7 +64,7 @@ class OperationsMiddleware(object):
request.route_cache = {} request.route_cache = {}
return request.route_cache return request.route_cache
return {} return {}
@classmethod @classmethod
def collect(cls, action, **kwargs): def collect(cls, action, **kwargs):
""" Collects all pending operations derived from model signals """ """ Collects all pending operations derived from model signals """
@ -75,26 +75,26 @@ class OperationsMiddleware(object):
kwargs['route_cache'] = cls.get_route_cache() kwargs['route_cache'] = cls.get_route_cache()
instance = kwargs.pop('instance') instance = kwargs.pop('instance')
manager.collect(instance, action, **kwargs) manager.collect(instance, action, **kwargs)
def enter_transaction_management(self): def enter_transaction_management(self):
type(self).thread_locals.transaction = transaction.atomic() type(self).thread_locals.transaction = transaction.atomic()
type(self).thread_locals.transaction.__enter__() type(self).thread_locals.transaction.__enter__()
def leave_transaction_management(self, exception=None): def leave_transaction_management(self, exception=None):
locals = type(self).thread_locals locals = type(self).thread_locals
if hasattr(locals, 'transaction'): if hasattr(locals, 'transaction'):
# Don't fucking know why sometimes thread_locals does not contain a transaction # Don't fucking know why sometimes thread_locals does not contain a transaction
locals.transaction.__exit__(exception, None, None) locals.transaction.__exit__(exception, None, None)
def process_request(self, request): def process_request(self, request):
""" Store request on a thread local variable """ """ Store request on a thread local variable """
type(self).thread_locals.request = request type(self).thread_locals.request = request
self.enter_transaction_management() self.enter_transaction_management()
def process_exception(self, request, exception): def process_exception(self, request, exception):
"""Rolls back the database and leaves transaction management""" """Rolls back the database and leaves transaction management"""
self.leave_transaction_management(exception) self.leave_transaction_management(exception)
def process_response(self, request, response): def process_response(self, request, response):
""" Processes pending backend operations """ """ Processes pending backend operations """
if response.status_code != 500: if response.status_code != 500:

View File

@ -1,5 +1,5 @@
from django.contrib import admin, messages from django.contrib import admin, messages
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import transaction from django.db import transaction
from django.utils import timezone from django.utils import timezone
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -17,7 +17,7 @@ class BillSelectedOrders(object):
verbose_name = _("Bill") verbose_name = _("Bill")
template = 'admin/orders/order/bill_selected_options.html' template = 'admin/orders/order/bill_selected_options.html'
__name__ = 'bill_selected_orders' __name__ = 'bill_selected_orders'
def __call__(self, modeladmin, request, queryset): def __call__(self, modeladmin, request, queryset):
""" make this monster behave like a function """ """ make this monster behave like a function """
self.modeladmin = modeladmin self.modeladmin = modeladmin
@ -34,7 +34,7 @@ class BillSelectedOrders(object):
del(self.queryset) del(self.queryset)
del(self.context) del(self.context)
return ret return ret
def set_options(self, request): def set_options(self, request):
form = BillSelectedOptionsForm() form = BillSelectedOptionsForm()
if request.POST.get('step'): if request.POST.get('step'):
@ -56,7 +56,7 @@ class BillSelectedOrders(object):
'form': form, 'form': form,
}) })
return render(request, self.template, self.context) return render(request, self.template, self.context)
def select_related(self, request): def select_related(self, request):
# TODO use changelist ? # TODO use changelist ?
related = self.queryset.get_related().select_related('account', 'service') related = self.queryset.get_related().select_related('account', 'service')
@ -76,7 +76,7 @@ class BillSelectedOrders(object):
'form': form, 'form': form,
}) })
return render(request, self.template, self.context) return render(request, self.template, self.context)
@transaction.atomic @transaction.atomic
def confirmation(self, request): def confirmation(self, request):
form = BillSelectConfirmationForm(initial=self.options) form = BillSelectConfirmationForm(initial=self.options)

View File

@ -1,13 +1,13 @@
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.db.models import Prefetch from django.db.models import Prefetch
from django.utils import timezone from django.utils import timezone
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.admin import ExtendedModelAdmin from orchestra.admin import ExtendedModelAdmin
from orchestra.admin.utils import admin_link, admin_date, change_url from orchestra.admin.utils import admin_link, admin_date, change_url
from orchestra.contrib.accounts.actions import list_accounts from orchestra.contrib.accounts.actions import list_accounts
from orchestra.contrib.accounts.admin import AccountAdminMixin from orchestra.contrib.accounts.admin import AccountAdminMixin
@ -22,10 +22,10 @@ class MetricStorageInline(admin.TabularInline):
model = MetricStorage model = MetricStorage
readonly_fields = ('value', 'created_on', 'updated_on') readonly_fields = ('value', 'created_on', 'updated_on')
extra = 0 extra = 0
def has_add_permission(self, request, obj=None): def has_add_permission(self, request, obj=None):
return False return False
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
if obj: if obj:
url = reverse('admin:orders_metricstorage_changelist') url = reverse('admin:orders_metricstorage_changelist')
@ -33,7 +33,7 @@ class MetricStorageInline(admin.TabularInline):
title = _('Metric storage, last 10 entries, <a href="%s">(See all)</a>') title = _('Metric storage, last 10 entries, <a href="%s">(See all)</a>')
self.verbose_name_plural = mark_safe(title % url) self.verbose_name_plural = mark_safe(title % url)
return super(MetricStorageInline, self).get_fieldsets(request, obj) return super(MetricStorageInline, self).get_fieldsets(request, obj)
def get_queryset(self, request): def get_queryset(self, request):
qs = super(MetricStorageInline, self).get_queryset(request) qs = super(MetricStorageInline, self).get_queryset(request)
change_view = bool(self.parent_object and self.parent_object.pk) change_view = bool(self.parent_object and self.parent_object.pk)
@ -106,17 +106,17 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
'content_object_repr', 'content_object_link', 'bills_links', 'account_link', 'content_object_repr', 'content_object_link', 'bills_links', 'account_link',
'service_link' 'service_link'
) )
service_link = admin_link('service') service_link = admin_link('service')
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')
def display_description(self, order): def display_description(self, order):
return order.description[:64] return order.description[:64]
display_description.short_description = _("Description") display_description.short_description = _("Description")
display_description.allow_tags = True display_description.allow_tags = True
display_description.admin_order_field = 'description' display_description.admin_order_field = 'description'
def content_object_link(self, order): def content_object_link(self, order):
if order.content_object: if order.content_object:
try: try:
@ -131,7 +131,7 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
content_object_link.short_description = _("Content object") content_object_link.short_description = _("Content object")
content_object_link.allow_tags = True content_object_link.allow_tags = True
content_object_link.admin_order_field = 'content_object_repr' content_object_link.admin_order_field = 'content_object_repr'
def bills_links(self, order): def bills_links(self, order):
bills = [] bills = []
make_link = admin_link() make_link = admin_link()
@ -140,7 +140,7 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
return '<br>'.join(bills) return '<br>'.join(bills)
bills_links.short_description = _("Bills") bills_links.short_description = _("Bills")
bills_links.allow_tags = True bills_links.allow_tags = True
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
@ -163,7 +163,7 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
display_billed_until.short_description = _("billed until") display_billed_until.short_description = _("billed until")
display_billed_until.allow_tags = True display_billed_until.allow_tags = True
display_billed_until.admin_order_field = 'billed_until' display_billed_until.admin_order_field = 'billed_until'
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
@ -174,7 +174,7 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
return '' return ''
return metric.value return metric.value
display_metric.short_description = _("Metric") 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 """
if db_field.name == 'description': if db_field.name == 'description':

View File

@ -2,7 +2,7 @@ from functools import partial
from django.contrib import messages from django.contrib import messages
from django.contrib.admin import actions from django.contrib.admin import actions
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -48,20 +48,20 @@ class TransactionInline(admin.TabularInline):
'amount', 'currency' 'amount', 'currency'
) )
readonly_fields = fields readonly_fields = fields
transaction_link = admin_link('__str__', short_description=_("ID")) transaction_link = admin_link('__str__', short_description=_("ID"))
bill_link = admin_link('bill') bill_link = admin_link('bill')
source_link = admin_link('source') source_link = admin_link('source')
display_state = admin_colored('state', colors=STATE_COLORS) display_state = admin_colored('state', colors=STATE_COLORS)
class Media: class Media:
css = { css = {
'all': ('orchestra/css/hide-inline-id.css',) 'all': ('orchestra/css/hide-inline-id.css',)
} }
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
def get_queryset(self, *args, **kwargs): def get_queryset(self, *args, **kwargs):
qs = super().get_queryset(*args, **kwargs) qs = super().get_queryset(*args, **kwargs)
return qs.select_related('source', 'bill') return qs.select_related('source', 'bill')
@ -116,28 +116,28 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
) )
list_select_related = ('source', 'bill__account', 'process') list_select_related = ('source', 'bill__account', 'process')
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
bill_link = admin_link('bill') bill_link = admin_link('bill')
source_link = admin_link('source') source_link = admin_link('source')
process_link = admin_link('process', short_description=_("proc")) process_link = admin_link('process', short_description=_("proc"))
account_link = admin_link('bill__account') account_link = admin_link('bill__account')
display_created_at = admin_date('created_at', short_description=_("Created")) display_created_at = admin_date('created_at', short_description=_("Created"))
display_modified_at = admin_date('modified_at', short_description=_("Modified")) display_modified_at = admin_date('modified_at', short_description=_("Modified"))
def has_delete_permission(self, *args, **kwargs): def has_delete_permission(self, *args, **kwargs):
return False return False
def get_actions(self, request): def get_actions(self, request):
actions = super().get_actions(request) actions = super().get_actions(request)
if 'delete_selected' in actions: if 'delete_selected' in actions:
del actions['delete_selected'] del actions['delete_selected']
return actions return actions
def get_change_readonly_fields(self, request, obj): def get_change_readonly_fields(self, request, obj):
if obj.state in (Transaction.WAITTING_PROCESSING, Transaction.WAITTING_EXECUTION): if obj.state in (Transaction.WAITTING_PROCESSING, Transaction.WAITTING_EXECUTION):
return () return ()
return ('amount', 'currency') return ('amount', 'currency')
def get_change_view_actions(self, obj=None): def get_change_view_actions(self, obj=None):
actions = super(TransactionAdmin, self).get_change_view_actions() actions = super(TransactionAdmin, self).get_change_view_actions()
exclude = [] exclude = []
@ -153,7 +153,7 @@ class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
elif obj.state == Transaction.SECURED: elif obj.state == Transaction.SECURED:
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]
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()
@ -178,16 +178,16 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
actions.mark_process_as_executed, actions.abort, actions.commit, actions.report actions.mark_process_as_executed, actions.abort, actions.commit, actions.report
) )
actions = change_view_actions + (actions.delete_selected,) actions = change_view_actions + (actions.delete_selected,)
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"))
def file_url(self, process): def file_url(self, process):
if process.file: if process.file:
return '<a href="%s">%s</a>' % (process.file.url, process.file.name) return '<a href="%s">%s</a>' % (process.file.url, process.file.name)
file_url.allow_tags = True file_url.allow_tags = True
file_url.admin_order_field = 'file' file_url.admin_order_field = 'file'
def display_transactions(self, process): def display_transactions(self, process):
ids = [] ids = []
lines = [] lines = []
@ -208,10 +208,10 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
return '<a href="%s">%s</a>' % (url, transactions) return '<a href="%s">%s</a>' % (url, transactions)
display_transactions.short_description = _("Transactions") display_transactions.short_description = _("Transactions")
display_transactions.allow_tags = True display_transactions.allow_tags = True
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
def get_change_view_actions(self, obj=None): def get_change_view_actions(self, obj=None):
actions = super().get_change_view_actions() actions = super().get_change_view_actions()
exclude = [] exclude = []
@ -223,7 +223,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
elif obj.state == TransactionProcess.ABORTED: elif obj.state == TransactionProcess.ABORTED:
exclude = ['mark_process_as_executed', 'abort', 'commit'] exclude = ['mark_process_as_executed', 'abort', 'commit']
return [action for action in actions if action.__name__ not in exclude] return [action for action in actions if action.__name__ not in exclude]
def delete_view(self, request, object_id, extra_context=None): def delete_view(self, request, object_id, extra_context=None):
queryset = self.model.objects.filter(id=object_id) queryset = self.model.objects.filter(id=object_id)
related_transactions = helpers.pre_delete_processes(self, request, queryset) related_transactions = helpers.pre_delete_processes(self, request, queryset)

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -28,7 +28,7 @@ class PlanAdmin(ExtendedModelAdmin):
} }
change_readonly_fields = ('name',) change_readonly_fields = ('name',)
inlines = [RateInline] inlines = [RateInline]
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')
@ -37,7 +37,7 @@ class PlanAdmin(ExtendedModelAdmin):
num_contracts.short_description = _("Contracts") num_contracts.short_description = _("Contracts")
num_contracts.admin_order_field = 'contracts__count' num_contracts.admin_order_field = 'contracts__count'
num_contracts.allow_tags = True num_contracts.allow_tags = True
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))
@ -49,7 +49,7 @@ class ContractedPlanAdmin(AccountAdminMixin, admin.ModelAdmin):
list_select_related = ('plan', 'account') list_select_related = ('plan', 'account')
search_fields = ('account__username', 'plan__name', 'id') search_fields = ('account__username', 'plan__name', 'id')
actions = (list_accounts,) actions = (list_accounts,)
plan_link = admin_link('plan') plan_link = admin_link('plan')

View File

@ -1,4 +1,4 @@
from django.core.urlresolvers import reverse from django.urls import reverse
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _

View File

@ -6,7 +6,7 @@ from django.contrib import admin, messages
from django.contrib.contenttypes.admin import GenericTabularInline from django.contrib.contenttypes.admin import GenericTabularInline
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet from django.contrib.contenttypes.forms import BaseGenericInlineFormSet
from django.contrib.admin.utils import unquote from django.contrib.admin.utils import unquote
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db.models import Q from django.db.models import Q
from django.shortcuts import redirect from django.shortcuts import redirect
from django.templatetags.static import static from django.templatetags.static import static
@ -58,7 +58,7 @@ class ResourceAdmin(ExtendedModelAdmin):
'name': ('verbose_name',) 'name': ('verbose_name',)
} }
list_select_related = ('content_type', 'crontab',) list_select_related = ('content_type', 'crontab',)
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url='', extra_context=None):
""" Remaind user when monitor routes are not configured """ """ Remaind user when monitor routes are not configured """
if request.method == 'GET': if request.method == 'GET':
@ -78,7 +78,7 @@ class ResourceAdmin(ExtendedModelAdmin):
}) })
return super(ResourceAdmin, self).change_view(request, object_id, form_url=form_url, return super(ResourceAdmin, self).change_view(request, object_id, form_url=form_url,
extra_context=extra_context) extra_context=extra_context)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
super(ResourceAdmin, self).save_model(request, obj, form, change) super(ResourceAdmin, self).save_model(request, obj, form, change)
# best-effort # best-effort
@ -93,7 +93,7 @@ class ResourceAdmin(ExtendedModelAdmin):
modeladmin.inlines = inlines modeladmin.inlines = inlines
# reload Not always work # reload Not always work
sys.touch_wsgi() sys.touch_wsgi()
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
""" filter service content_types """ """ filter service content_types """
if db_field.name == 'content_type': if db_field.name == 'content_type':
@ -127,10 +127,10 @@ class ResourceDataAdmin(ExtendedModelAdmin):
change_view_actions = actions change_view_actions = actions
ordering = ('-updated_at',) ordering = ('-updated_at',)
list_select_related = ('resource__content_type', 'content_type') list_select_related = ('resource__content_type', 'content_type')
resource_link = admin_link('resource') resource_link = admin_link('resource')
display_updated = admin_date('updated_at', short_description=_("Updated")) display_updated = admin_date('updated_at', short_description=_("Updated"))
def get_urls(self): def get_urls(self):
"""Returns the additional urls for the change view links""" """Returns the additional urls for the change view links"""
urls = super(ResourceDataAdmin, self).get_urls() urls = super(ResourceDataAdmin, self).get_urls()
@ -150,7 +150,7 @@ class ResourceDataAdmin(ExtendedModelAdmin):
name='%s_%s_list_related' % (opts.app_label, opts.model_name) name='%s_%s_list_related' % (opts.app_label, opts.model_name)
), ),
] + urls ] + urls
def display_used(self, rdata): def display_used(self, rdata):
if rdata.used is None: if rdata.used is None:
return '' return ''
@ -159,15 +159,15 @@ class ResourceDataAdmin(ExtendedModelAdmin):
display_used.short_description = _("Used") display_used.short_description = _("Used")
display_used.admin_order_field = 'used' display_used.admin_order_field = 'used'
display_used.allow_tags = True display_used.allow_tags = True
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
return False return False
def used_monitordata_view(self, request, object_id): def used_monitordata_view(self, request, object_id):
url = reverse('admin:resources_monitordata_changelist') url = reverse('admin:resources_monitordata_changelist')
url += '?resource_data=%s' % object_id url += '?resource_data=%s' % object_id
return redirect(url) return redirect(url)
def list_related_view(self, request, app_name, model_name, object_id): def list_related_view(self, request, app_name, model_name, object_id):
resources = Resource.objects.select_related('content_type') resources = Resource.objects.select_related('content_type')
resource_models = {r.content_type.model_class(): r.content_type_id for r in resources} resource_models = {r.content_type.model_class(): r.content_type_id for r in resources}
@ -203,9 +203,9 @@ class MonitorDataAdmin(ExtendedModelAdmin):
list_select_related = ('content_type',) list_select_related = ('content_type',)
search_fields = ('content_object_repr',) search_fields = ('content_object_repr',)
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
display_created = admin_date('created_at', short_description=_("Created")) display_created = admin_date('created_at', short_description=_("Created"))
def filter_used_monitordata(self, request, queryset): def filter_used_monitordata(self, request, queryset):
query_string = parse_qs(request.META['QUERY_STRING']) query_string = parse_qs(request.META['QUERY_STRING'])
resource_data = query_string.get('resource_data') resource_data = query_string.get('resource_data')
@ -221,7 +221,7 @@ class MonitorDataAdmin(ExtendedModelAdmin):
ids += dataset.values_list('id', flat=True) ids += dataset.values_list('id', flat=True)
return queryset.filter(id__in=ids) return queryset.filter(id__in=ids)
return queryset return queryset
def get_queryset(self, request): def get_queryset(self, request):
queryset = super(MonitorDataAdmin, self).get_queryset(request) queryset = super(MonitorDataAdmin, self).get_queryset(request)
queryset = self.filter_used_monitordata(request, queryset) queryset = self.filter_used_monitordata(request, queryset)
@ -239,13 +239,13 @@ def resource_inline_factory(resources):
class ResourceInlineFormSet(BaseGenericInlineFormSet): class ResourceInlineFormSet(BaseGenericInlineFormSet):
def total_form_count(self, resources=resources): def total_form_count(self, resources=resources):
return len(resources) return len(resources)
@cached @cached
def get_queryset(self): def get_queryset(self):
""" Filter disabled resources """ """ Filter disabled resources """
queryset = super(ResourceInlineFormSet, self).get_queryset() queryset = super(ResourceInlineFormSet, self).get_queryset()
return queryset.filter(resource__is_active=True).select_related('resource') return queryset.filter(resource__is_active=True).select_related('resource')
@cached_property @cached_property
def forms(self, resources=resources): def forms(self, resources=resources):
forms = [] forms = []
@ -276,7 +276,7 @@ def resource_inline_factory(resources):
for i, resource in enumerate(resources_copy, len(queryset)): for i, resource in enumerate(resources_copy, len(queryset)):
forms.append(self._construct_form(i, resource=resource)) forms.append(self._construct_form(i, resource=resource))
return forms return forms
class ResourceInline(GenericTabularInline): class ResourceInline(GenericTabularInline):
model = ResourceData model = ResourceData
verbose_name_plural = _("resources") verbose_name_plural = _("resources")
@ -287,14 +287,14 @@ def resource_inline_factory(resources):
'verbose_name', 'display_used', 'display_updated', 'allocated', 'unit', 'verbose_name', 'display_used', 'display_updated', 'allocated', 'unit',
) )
readonly_fields = ('display_used', 'display_updated',) readonly_fields = ('display_used', 'display_updated',)
class Media: class Media:
css = { css = {
'all': ('orchestra/css/hide-inline-id.css',) 'all': ('orchestra/css/hide-inline-id.css',)
} }
display_updated = admin_date('updated_at', default=_("Never")) display_updated = admin_date('updated_at', default=_("Never"))
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
if obj: if obj:
opts = self.parent_model._meta opts = self.parent_model._meta
@ -303,7 +303,7 @@ def resource_inline_factory(resources):
link = '<a href="%s">%s</a>' % (url, _("List related")) link = '<a href="%s">%s</a>' % (url, _("List related"))
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)
def display_used(self, rdata): def display_used(self, rdata):
update = '' update = ''
history = '' history = ''
@ -330,11 +330,11 @@ def resource_inline_factory(resources):
return _("No monitor") return _("No monitor")
display_used.short_description = _("Used") display_used.short_description = _("Used")
display_used.allow_tags = True display_used.allow_tags = True
def has_add_permission(self, *args, **kwargs): def has_add_permission(self, *args, **kwargs):
""" Hidde add another """ """ Hidde add another """
return False return False
return ResourceInline return ResourceInline

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db.models import Q from django.db.models import Q
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -25,7 +25,7 @@ class PHPListForm(SaaSPasswordForm):
help_text=_("Dedicated mailbox used for reciving bounces."), help_text=_("Dedicated mailbox used for reciving bounces."),
widget=SpanWidget(display=settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME.replace( widget=SpanWidget(display=settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME.replace(
'%(', '&lt;').replace(')s', '&gt;'))) '%(', '&lt;').replace(')s', '&gt;')))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PHPListForm, self).__init__(*args, **kwargs) super(PHPListForm, self).__init__(*args, **kwargs)
self.fields['name'].label = _("Site name") self.fields['name'].label = _("Site name")
@ -76,14 +76,14 @@ class PHPListService(DBSoftwareService):
allow_custom_url = settings.SAAS_PHPLIST_ALLOW_CUSTOM_URL allow_custom_url = settings.SAAS_PHPLIST_ALLOW_CUSTOM_URL
db_name = settings.SAAS_PHPLIST_DB_NAME db_name = settings.SAAS_PHPLIST_DB_NAME
db_user = settings.SAAS_PHPLIST_DB_USER db_user = settings.SAAS_PHPLIST_DB_USER
def get_mailbox_name(self): def get_mailbox_name(self):
context = { context = {
'name': self.instance.name, 'name': self.instance.name,
'site_name': self.instance.name, 'site_name': self.instance.name,
} }
return settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME % context return settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME % context
def validate(self): def validate(self):
super(PHPListService, self).validate() super(PHPListService, self).validate()
create = not self.instance.pk create = not self.instance.pk
@ -97,7 +97,7 @@ class PHPListService(DBSoftwareService):
raise ValidationError({ raise ValidationError({
'name': e.messages, 'name': e.messages,
}) })
def save(self): def save(self):
super(PHPListService, self).save() super(PHPListService, self).save()
account = self.get_account() account = self.get_account()
@ -111,7 +111,7 @@ class PHPListService(DBSoftwareService):
'mailbox_id': mailbox.pk, 'mailbox_id': mailbox.pk,
'mailbox_name': mailbox_name, 'mailbox_name': mailbox_name,
}) })
def delete(self): def delete(self):
super(PHPListService, self).save() super(PHPListService, self).save()
account = self.get_account() account = self.get_account()

View File

@ -1,5 +1,5 @@
from django.contrib.admin import helpers from django.contrib.admin import helpers
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.conf.urls import url from django.conf.urls import url
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -42,7 +42,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
actions = (update_orders, clone, disable, enable) actions = (update_orders, clone, disable, enable)
change_view_actions = actions + (view_help,) change_view_actions = actions + (view_help,)
change_form_template = 'admin/services/service/change_form.html' change_form_template = 'admin/services/service/change_form.html'
def get_urls(self): def get_urls(self):
"""Returns the additional urls for the change view links""" """Returns the additional urls for the change view links"""
urls = super(ServiceAdmin, self).get_urls() urls = super(ServiceAdmin, self).get_urls()
@ -54,7 +54,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
name='%s_%s_help' % (opts.app_label, opts.model_name) name='%s_%s_help' % (opts.app_label, opts.model_name)
) )
] + urls ] + urls
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
""" Improve performance of account field and filter by account """ """ Improve performance of account field and filter by account """
if db_field.name == 'content_type': if db_field.name == 'content_type':
@ -64,7 +64,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
if db_field.name in ['match', 'metric', 'order_description']: if db_field.name in ['match', 'metric', 'order_description']:
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)
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')
@ -73,7 +73,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
num_orders.short_description = _("Orders") num_orders.short_description = _("Orders")
num_orders.admin_order_field = 'orders__count' num_orders.admin_order_field = 'orders__count'
num_orders.allow_tags = True num_orders.allow_tags = True
def get_queryset(self, request): def get_queryset(self, request):
qs = super(ServiceAdmin, self).get_queryset(request) qs = super(ServiceAdmin, self).get_queryset(request)
# Count active orders # Count active orders
@ -88,7 +88,7 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
) )
}) })
return qs return qs
def help_view(self, request, *args): def help_view(self, request, *args):
opts = self.model._meta opts = self.model._meta
context = { context = {

View File

@ -8,7 +8,7 @@ from functools import partial
import paramiko import paramiko
from django.conf import settings as djsettings from django.conf import settings as djsettings
from django.core.management.base import CommandError from django.core.management.base import CommandError
from django.core.urlresolvers import reverse from django.urls import reverse
from selenium.webdriver.support.select import Select from selenium.webdriver.support.select import Select
from orchestra.admin.utils import change_url from orchestra.admin.utils import change_url

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
@ -21,16 +21,16 @@ from .types import AppType
class WebAppOptionInline(admin.TabularInline): class WebAppOptionInline(admin.TabularInline):
model = WebAppOption model = WebAppOption
extra = 1 extra = 1
OPTIONS_HELP_TEXT = { OPTIONS_HELP_TEXT = {
op.name: force_text(op.help_text) for op in AppOption.get_plugins() op.name: force_text(op.help_text) for op in AppOption.get_plugins()
} }
class Media: class Media:
css = { css = {
'all': ('orchestra/css/hide-inline-id.css',) 'all': ('orchestra/css/hide-inline-id.css',)
} }
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'value': if db_field.name == 'value':
kwargs['widget'] = forms.TextInput(attrs={'size':'100'}) kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
@ -63,9 +63,9 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
plugin_field = 'type' plugin_field = 'type'
plugin_title = _("Web application type") plugin_title = _("Web application type")
actions = (list_accounts,) actions = (list_accounts,)
display_type = display_plugin_field('type') display_type = display_plugin_field('type')
def display_websites(self, webapp): def display_websites(self, webapp):
websites = [] websites = []
for content in webapp.content_set.all(): for content in webapp.content_set.all():
@ -83,7 +83,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
return '<br>'.join(websites) return '<br>'.join(websites)
display_websites.short_description = _("web sites") display_websites.short_description = _("web sites")
display_websites.allow_tags = True display_websites.allow_tags = True
def display_detail(self, webapp): def display_detail(self, webapp):
try: try:
return webapp.type_instance.get_detail() return webapp.type_instance.get_detail()
@ -91,11 +91,11 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
return "<span style='color:red;'>Not available</span>" return "<span style='color:red;'>Not available</span>"
display_detail.short_description = _("detail") display_detail.short_description = _("detail")
display_detail.allow_tags = True display_detail.allow_tags = True
# def get_form(self, request, obj=None, **kwargs): # def get_form(self, request, obj=None, **kwargs):
# form = super(WebAppAdmin, self).get_form(request, obj, **kwargs) # form = super(WebAppAdmin, self).get_form(request, obj, **kwargs)
# if obj: # if obj:
# #
# 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 """

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
@ -20,7 +20,7 @@ class CMSAppForm(PHPAppForm):
password = forms.CharField(label=_("Password"), password = forms.CharField(label=_("Password"),
help_text=_("Initial database and WordPress admin password.<br>" help_text=_("Initial database and WordPress admin password.<br>"
"Subsequent changes to the admin password will not be reflected.")) "Subsequent changes to the admin password will not be reflected."))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CMSAppForm, self).__init__(*args, **kwargs) super(CMSAppForm, self).__init__(*args, **kwargs)
if self.instance: if self.instance:
@ -55,20 +55,20 @@ class CMSApp(PHPApp):
db_type = Database.MYSQL db_type = Database.MYSQL
abstract = True abstract = True
db_prefix = 'cms_' db_prefix = 'cms_'
def get_db_name(self): def get_db_name(self):
db_name = '%s%s_%s' % (self.db_prefix, self.instance.name, self.instance.account) db_name = '%s%s_%s' % (self.db_prefix, self.instance.name, self.instance.account)
# Limit for mysql database names # Limit for mysql database names
return db_name[:65] return db_name[:65]
def get_db_user(self): def get_db_user(self):
db_name = self.get_db_name() db_name = self.get_db_name()
# Limit for mysql user names # Limit for mysql user names
return db_name[:16] return db_name[:16]
def get_password(self): def get_password(self):
return random_ascii(10) return random_ascii(10)
def validate(self): def validate(self):
super(CMSApp, self).validate() super(CMSApp, self).validate()
create = not self.instance.pk create = not self.instance.pk
@ -83,7 +83,7 @@ class CMSApp(PHPApp):
raise ValidationError({ raise ValidationError({
'name': e.messages, 'name': e.messages,
}) })
def save(self): def save(self):
db_name = self.get_db_name() db_name = self.get_db_name()
db_user = self.get_db_user() db_user = self.get_db_user()

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import resolve from django.urls import resolve
from django.db.models import Q from django.db.models import Q
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -24,11 +24,11 @@ class WebsiteDirectiveInline(admin.TabularInline):
model = WebsiteDirective model = WebsiteDirective
formset = WebsiteDirectiveInlineFormSet formset = WebsiteDirectiveInlineFormSet
extra = 1 extra = 1
DIRECTIVES_HELP_TEXT = { DIRECTIVES_HELP_TEXT = {
op.name: force_text(op.help_text) for op in SiteDirective.get_plugins() op.name: force_text(op.help_text) for op in SiteDirective.get_plugins()
} }
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'value': if db_field.name == 'value':
kwargs['widget'] = forms.TextInput(attrs={'size':'100'}) kwargs['widget'] = forms.TextInput(attrs={'size':'100'})
@ -45,10 +45,10 @@ class ContentInline(AccountAdminMixin, admin.TabularInline):
fields = ('webapp', 'webapp_link', 'webapp_type', 'path') fields = ('webapp', 'webapp_link', 'webapp_type', 'path')
readonly_fields = ('webapp_link', 'webapp_type') readonly_fields = ('webapp_link', 'webapp_type')
filter_by_account_fields = ['webapp'] filter_by_account_fields = ['webapp']
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")
def webapp_type(self, content): def webapp_type(self, content):
if not content.pk: if not content.pk:
return '' return ''
@ -77,7 +77,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
list_prefetch_related = ('domains', 'content_set__webapp') list_prefetch_related = ('domains', 'content_set__webapp')
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)
def display_domains(self, website): def display_domains(self, website):
domains = [] domains = []
for domain in website.domains.all(): for domain in website.domains.all():
@ -87,7 +87,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
display_domains.short_description = _("domains") display_domains.short_description = _("domains")
display_domains.allow_tags = True display_domains.allow_tags = True
display_domains.admin_order_field = 'domains' display_domains.admin_order_field = 'domains'
def display_webapps(self, website): def display_webapps(self, website):
webapps = [] webapps = []
for content in website.content_set.all(): for content in website.content_set.all():
@ -104,7 +104,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
return '<br>'.join(webapps) return '<br>'.join(webapps)
display_webapps.allow_tags = True display_webapps.allow_tags = True
display_webapps.short_description = _("Web apps") display_webapps.short_description = _("Web apps")
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
""" """
Exclude domains with exhausted ports Exclude domains with exhausted ports
@ -124,7 +124,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
qset = Q(qset & ~Q(websites__pk=object_id)) qset = Q(qset & ~Q(websites__pk=object_id))
formfield.queryset = formfield.queryset.exclude(qset) formfield.queryset = formfield.queryset.exclude(qset)
return formfield return formfield
def _create_formsets(self, request, obj, change): def _create_formsets(self, request, obj, change):
""" bind contents formset to directive formset for unique location cross-validation """ """ bind contents formset to directive formset for unique location cross-validation """
formsets, inline_instances = super(WebsiteAdmin, self)._create_formsets(request, obj, change) formsets, inline_instances = super(WebsiteAdmin, self)._create_formsets(request, obj, change)

View File

@ -1,7 +1,7 @@
import os import os
from django.core import exceptions from django.core import exceptions
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.db.models.fields.files import FileField, FieldFile from django.db.models.fields.files import FileField, FieldFile
from django.utils.text import capfirst from django.utils.text import capfirst
@ -21,34 +21,34 @@ class MultiSelectField(models.CharField):
defaults['initial'] = self.get_default() defaults['initial'] = self.get_default()
defaults.update(kwargs) defaults.update(kwargs)
return MultiSelectFormField(**defaults) return MultiSelectFormField(**defaults)
def get_db_prep_value(self, value, connection=None, prepared=False): def get_db_prep_value(self, value, connection=None, prepared=False):
if isinstance(value, str): if isinstance(value, str):
return value return value
else: else:
return ','.join(value) return ','.join(value)
def to_python(self, value): def to_python(self, value):
if value: if value:
if isinstance(value, str): if isinstance(value, str):
return value.split(',') return value.split(',')
return value return value
return [] return []
def from_db_value(self, value, expression, connection, context): def from_db_value(self, value, expression, connection, context):
if value: if value:
if isinstance(value, str): if isinstance(value, str):
return value.split(',') return value.split(',')
return value return value
return [] return []
def contribute_to_class(self, cls, name): def contribute_to_class(self, cls, name):
super(MultiSelectField, self).contribute_to_class(cls, name) super(MultiSelectField, self).contribute_to_class(cls, name)
if self.choices: if self.choices:
def func(self, field=name, choices=dict(self.choices)): def func(self, field=name, choices=dict(self.choices)):
return ','.join([choices.get(value, value) for value in getattr(self, field)]) return ','.join([choices.get(value, value) for value in getattr(self, field)])
setattr(cls, 'get_%s_display' % self.name, func) setattr(cls, 'get_%s_display' % self.name, func)
def validate(self, value, model_instance): def validate(self, value, model_instance):
if self.choices: if self.choices:
arr_choices = self.get_choices_selected(self.get_choices()) arr_choices = self.get_choices_selected(self.get_choices())
@ -56,7 +56,7 @@ class MultiSelectField(models.CharField):
if (opt_select not in arr_choices): if (opt_select not in arr_choices):
msg = self.error_messages['invalid_choice'] % {'value': opt_select} msg = self.error_messages['invalid_choice'] % {'value': opt_select}
raise exceptions.ValidationError(msg) raise exceptions.ValidationError(msg)
def get_choices_selected(self, arr_choices=''): def get_choices_selected(self, arr_choices=''):
if not arr_choices: if not arr_choices:
return False return False
@ -79,11 +79,11 @@ class PrivateFieldFile(FieldFile):
filename = os.path.basename(self.path) filename = os.path.basename(self.path)
args = [app_label, model_name, field_name, pk, filename] args = [app_label, model_name, field_name, pk, filename]
return reverse('private-media', args=args) return reverse('private-media', args=args)
@property @property
def condition(self): def condition(self):
return self.field.condition return self.field.condition
@property @property
def attachment(self): def attachment(self):
return self.field.attachment return self.field.attachment
@ -91,7 +91,7 @@ class PrivateFieldFile(FieldFile):
class PrivateFileField(FileField): class PrivateFileField(FileField):
attr_class = PrivateFieldFile attr_class = PrivateFieldFile
def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, attachment=True, def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, attachment=True,
condition=lambda request, instance: request.user.is_superuser, **kwargs): condition=lambda request, instance: request.user.is_superuser, **kwargs):
super(PrivateFileField, self).__init__(verbose_name, name, upload_to, storage, **kwargs) super(PrivateFileField, self).__init__(verbose_name, name, upload_to, storage, **kwargs)

View File

@ -1,16 +1,16 @@
from django.core.urlresolvers import resolve from django.urls import resolve
from rest_framework.permissions import DjangoModelPermissions from rest_framework.permissions import DjangoModelPermissions
class OrchestraPermissionBackend(DjangoModelPermissions): class OrchestraPermissionBackend(DjangoModelPermissions):
""" Permissions according to each user """ """ Permissions according to each user """
def has_permission(self, request, view): def has_permission(self, request, view):
queryset = getattr(view, 'queryset', None) queryset = getattr(view, 'queryset', None)
if queryset is None: if queryset is None:
name = resolve(request.path).url_name name = resolve(request.path).url_name
return name == 'api-root' return name == 'api-root'
model_cls = queryset.model model_cls = queryset.model
perms = self.get_required_permissions(request.method, model_cls) perms = self.get_required_permissions(request.method, model_cls)
if (request.user and if (request.user and
@ -18,7 +18,7 @@ class OrchestraPermissionBackend(DjangoModelPermissions):
request.user.has_perms(perms, model_cls)): request.user.has_perms(perms, model_cls)):
return True return True
return False return False
def has_object_permission(self, request, view, obj): def has_object_permission(self, request, view, obj):
perms = self.get_required_permissions(request.method, type(obj)) perms = self.get_required_permissions(request.method, type(obj))
if (request.user and if (request.user and

View File

@ -4,7 +4,7 @@ import re
from django import template from django import template
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
from django.forms import CheckboxInput from django.forms import CheckboxInput
from django.template.base import Node from django.template.base import Node
from django.template.defaultfilters import date from django.template.defaultfilters import date
@ -54,7 +54,7 @@ def rest_to_admin_url(context):
class OneLinerNode(Node): class OneLinerNode(Node):
def __init__(self, nodelist): def __init__(self, nodelist):
self.nodelist = nodelist self.nodelist = nodelist
def render(self, context): def render(self, context):
line = self.nodelist.render(context).replace('\n', ' ') line = self.nodelist.render(context).replace('\n', ' ')
return re.sub(r'\s\s+', '', line) return re.sub(r'\s\s+', '', line)

View File

@ -5,7 +5,7 @@ from functools import wraps
from django.conf import settings from django.conf import settings
from django.contrib.auth import BACKEND_SESSION_KEY, SESSION_KEY from django.contrib.auth import BACKEND_SESSION_KEY, SESSION_KEY
from django.contrib.sessions.backends.db import SessionStore from django.contrib.sessions.backends.db import SessionStore
from django.core.urlresolvers import reverse from django.urls import reverse
from django.test import LiveServerTestCase, TestCase from django.test import LiveServerTestCase, TestCase
from selenium.webdriver.firefox.webdriver import WebDriver from selenium.webdriver.firefox.webdriver import WebDriver
from xvfbwrapper import Xvfb from xvfbwrapper import Xvfb