diff --git a/TODO.md b/TODO.md index 9ba640e1..a5e52152 100644 --- a/TODO.md +++ b/TODO.md @@ -464,5 +464,3 @@ with open(file) as handler: # Mark transaction process as executed should not override higher transaction states # mailbox.addresses get_Queryset SQL contact @ with mailboxes and forwards - -# Remove membership fee when changing account.type diff --git a/orchestra/contrib/accounts/admin.py b/orchestra/contrib/accounts/admin.py index 6df66eab..3214ccd4 100644 --- a/orchestra/contrib/accounts/admin.py +++ b/orchestra/contrib/accounts/admin.py @@ -17,8 +17,10 @@ from django.utils.translation import ugettext_lazy as _ from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin from orchestra.admin.actions import SendEmail from orchestra.admin.utils import wrap_admin_view, admin_link, set_url_query +from orchestra.contrib.services.settings import SERVICES_IGNORE_ACCOUNT_TYPE from orchestra.core import services, accounts from orchestra.forms import UserChangeForm +from orchestra.utils.apps import isinstalled from .actions import (list_contacts, service_report, delete_related_services, disable_selected, enable_selected) @@ -111,6 +113,26 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin) form.save_model(obj) form.save_related(obj) else: + if isinstalled('orchestra.contrib.orders') and isinstalled('orchestra.contrib.services'): + if 'type' in form.changed_data: + old_type = Account.objects.get(pk=obj.pk).type + new_type = form.cleaned_data['type'] + context = { + 'from': old_type.lower(), + 'to': new_type.lower(), + 'url': reverse('admin:orders_order_changelist'), + } + msg = '' + if old_type in SERVICES_IGNORE_ACCOUNT_TYPE and new_type not in SERVICES_IGNORE_ACCOUNT_TYPE: + context['url'] += '?account=%i&ignore=1' % obj.pk + msg = _("Account type has been changed from %(from)s to %(to)s. " + "You may want to mark existing ignored orders as not ignored.") + elif old_type not in SERVICES_IGNORE_ACCOUNT_TYPE and new_type in SERVICES_IGNORE_ACCOUNT_TYPE: + context['url'] += '?account=%i&ignore=0' % obj.pk + msg = _("Account type has been changed from %(from)s to %(to)s. " + "You may want to ignore existing not ignored orders.") + if msg: + messages.warning(request, mark_safe(msg % context)) super(AccountAdmin, self).save_model(request, obj, form, change) def get_change_view_actions(self, obj=None): diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py index 7c45e3d8..d6965655 100644 --- a/orchestra/contrib/mailboxes/admin.py +++ b/orchestra/contrib/mailboxes/admin.py @@ -89,7 +89,6 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo if cached_forwards is None: cached_forwards = {} qs = Address.objects.filter(forward__regex=r'(^|.*\s)[^@]+(\s.*|$)') - qs = qs.select_related('domain') qs = qs.annotate(email=Concat('name', V('@'), 'domain__name')) qs = qs.values_list('id', 'email', 'forward') for addr_id, email, mbox in qs: diff --git a/orchestra/contrib/webapps/admin.py b/orchestra/contrib/webapps/admin.py index 12e3aaee..0297ae8b 100644 --- a/orchestra/contrib/webapps/admin.py +++ b/orchestra/contrib/webapps/admin.py @@ -12,7 +12,7 @@ from orchestra.forms.widgets import DynamicHelpTextSelect from orchestra.plugins.admin import SelectPluginAdminMixin, display_plugin_field from orchestra.utils.html import get_on_site_link -from .filters import HasWebsiteListFilter, PHPVersionListFilter +from .filters import HasWebsiteListFilter, DetailListFilter from .models import WebApp, WebAppOption from .options import AppOption from .types import AppType @@ -53,7 +53,7 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin) list_display = ( 'name', 'display_type', 'display_detail', 'display_websites', 'account_link' ) - list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter) + list_filter = ('type', HasWebsiteListFilter, DetailListFilter) inlines = [WebAppOptionInline] readonly_fields = ('account_link',) change_readonly_fields = ('name', 'type', 'display_websites') diff --git a/orchestra/contrib/webapps/filters.py b/orchestra/contrib/webapps/filters.py index fca86d6b..bbf1cce3 100644 --- a/orchestra/contrib/webapps/filters.py +++ b/orchestra/contrib/webapps/filters.py @@ -1,7 +1,7 @@ from django.contrib.admin import SimpleListFilter from django.utils.translation import ugettext_lazy as _ -from . import settings +from .types import AppType class HasWebsiteListFilter(SimpleListFilter): @@ -22,15 +22,28 @@ class HasWebsiteListFilter(SimpleListFilter): return queryset -class PHPVersionListFilter(SimpleListFilter): - title = _("PHP version") - parameter_name = 'php_version' +class DetailListFilter(SimpleListFilter): + title = _("detail") + parameter_name = 'detail' def lookups(self, request, model_admin): - return settings.WEBAPPS_PHP_VERSIONS + ret = set() + lookup_map = {} + for apptype in AppType.get_plugins(): + for field, values in apptype.get_detail_lookups().items(): + for value in values: + lookup_map[value[0]] = field + ret.add(value) + self.lookup_map = lookup_map + return sorted(list(ret)) def queryset(self, request, queryset): value = self.value() if value: - return queryset.filter(data__contains='"php_version":"%s"' % value) + try: + field = self.lookup_map[value] + except KeyError: + return queryset + else: + return queryset.filter(data__contains='"%s":"%s"' % (field, value)) return queryset diff --git a/orchestra/contrib/webapps/types/__init__.py b/orchestra/contrib/webapps/types/__init__.py index 4e07a2a9..33020d32 100644 --- a/orchestra/contrib/webapps/types/__init__.py +++ b/orchestra/contrib/webapps/types/__init__.py @@ -72,6 +72,11 @@ class AppType(plugins.Plugin, metaclass=plugins.PluginMount): else: yield (group, [(op.name, op.verbose_name) for op in options]) + @classmethod + def get_detail_lookups(cls): + """ {'field_name': (('opt1', _("Option 1"),)} """ + return {} + def get_detail(self): return '' diff --git a/orchestra/contrib/webapps/types/php.py b/orchestra/contrib/webapps/types/php.py index 5764f276..8c1e6522 100644 --- a/orchestra/contrib/webapps/types/php.py +++ b/orchestra/contrib/webapps/types/php.py @@ -59,6 +59,12 @@ class PHPApp(AppType): def get_detail(self): return self.instance.data.get('php_version', '') + @classmethod + def get_detail_lookups(cls): + return { + 'php_version': settings.WEBAPPS_PHP_VERSIONS, + } + @cached def get_options(self, merge=settings.WEBAPPS_MERGE_PHP_WEBAPPS): """ adapter to webapp.get_options that performs merging of PHP options """ diff --git a/orchestra/contrib/webapps/types/python.py b/orchestra/contrib/webapps/types/python.py index d515f777..ec9984e4 100644 --- a/orchestra/contrib/webapps/types/python.py +++ b/orchestra/contrib/webapps/types/python.py @@ -40,6 +40,12 @@ class PythonApp(AppType): option_groups = (AppOption.FILESYSTEM, AppOption.PROCESS) icon = 'orchestra/icons/apps/Python.png' + @classmethod + def get_detail_lookups(cls): + return { + 'python_version': settings.WEBAPPS_PYTHON_VERSIONS, + } + def get_directive(self): context = self.get_directive_context() return ('uwsgi', settings.WEBAPPS_UWSGI_SOCKET % context)