diff --git a/TODO.md b/TODO.md index 28461b3c..9ba640e1 100644 --- a/TODO.md +++ b/TODO.md @@ -463,4 +463,6 @@ with open(file) as handler: # Mark transaction process as executed should not override higher transaction states -# Show password and set password management commands -sam -A|--all --systemuser --account --mailbox vs raw passwords on forms +# mailbox.addresses get_Queryset SQL contact @ with mailboxes and forwards + +# Remove membership fee when changing account.type diff --git a/orchestra/admin/options.py b/orchestra/admin/options.py index 3bce46f9..deee5194 100644 --- a/orchestra/admin/options.py +++ b/orchestra/admin/options.py @@ -285,8 +285,7 @@ class ChangePasswordAdminMixin(object): form = self.change_password_form(obj, request.POST, related=related, raw=raw) if form.is_valid(): form.save() - change_message = self.construct_change_message(request, form, None) - self.log_change(request, obj, change_message) + self.log_change(request, obj, _("Password changed.")) msg = _('Password changed successfully.') messages.success(request, msg) update_session_auth_hash(request, form.user) # This is safe diff --git a/orchestra/contrib/history/admin.py b/orchestra/contrib/history/admin.py index 430eb9aa..7d2b86e5 100644 --- a/orchestra/contrib/history/admin.py +++ b/orchestra/contrib/history/admin.py @@ -15,6 +15,7 @@ class LogEntryAdmin(admin.ModelAdmin): ) list_filter = ( 'action_flag', + ('user', admin.RelatedOnlyFieldListFilter), ('content_type', admin.RelatedOnlyFieldListFilter), ) date_hierarchy = 'action_time' diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py index a3a01fde..7c45e3d8 100644 --- a/orchestra/contrib/mailboxes/admin.py +++ b/orchestra/contrib/mailboxes/admin.py @@ -15,6 +15,7 @@ from orchestra.admin.utils import admin_link, change_url from orchestra.contrib.accounts.actions import list_accounts from orchestra.contrib.accounts.admin import SelectAccountAdminMixin from orchestra.contrib.accounts.filters import IsActiveListFilter +from orchestra.core import caches from . import settings from .actions import SendMailboxEmail, SendAddressEmail @@ -82,11 +83,33 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo type(self).actions = self.actions + (SendMailboxEmail(),) def display_addresses(self, mailbox): + # Get from forwards + cache = caches.get_request_cache() + cached_forwards = cache.get('forwards') + 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: + url = reverse('admin:mailboxes_address_change', args=(addr_id,)) + link = '%s' % (url, email) + try: + cached_forwards[mbox].append(link) + except KeyError: + cached_forwards[mbox] = [link] + cache.set('forwards', cached_forwards) + try: + forwards = cached_forwards[mailbox.name] + except KeyError: + forwards = [] + # Get from mailboxes addresses = [] for addr in mailbox.addresses.all(): url = change_url(addr) addresses.append('%s' % (url, addr.email)) - return '
'.join(addresses) + return '
'.join(addresses+forwards) display_addresses.short_description = _("Addresses") display_addresses.allow_tags = True diff --git a/orchestra/contrib/mailboxes/backends.py b/orchestra/contrib/mailboxes/backends.py index 773e7661..ebef95e1 100644 --- a/orchestra/contrib/mailboxes/backends.py +++ b/orchestra/contrib/mailboxes/backends.py @@ -70,7 +70,7 @@ class UNIXUserMaildirController(SieveFilteringMixin, ServiceController): # Update/create %(user)s user state if id %(user)s ; then old_password=$(getent shadow %(user)s | cut -d':' -f2) - usermod %(user)s \\ + usermod %(user)s \\ --shell %(initial_shell)s \\ --password '%(password)s' if [[ "$old_password" != '%(password)s' ]]; then diff --git a/orchestra/contrib/orchestration/managers.py b/orchestra/contrib/orchestration/managers.py index c91847da..f91ae291 100644 --- a/orchestra/contrib/orchestration/managers.py +++ b/orchestra/contrib/orchestration/managers.py @@ -35,6 +35,14 @@ def m2m_collector(sender, *args, **kwargs): class orchestrate(ContextDecorator): + """ + Context manager for triggering backend operations out of request-response cycle, e.g. shell + + with orchestrate(): + user = SystemUser.objects.get(username='rata') + user.shell = '/dev/null' + user.save(update_fields=('shell',)) + """ thread_locals = local() thread_locals.pending_operations = None thread_locals.route_cache = None diff --git a/orchestra/contrib/orders/admin.py b/orchestra/contrib/orders/admin.py index 024cbc5f..a2918f11 100644 --- a/orchestra/contrib/orders/admin.py +++ b/orchestra/contrib/orders/admin.py @@ -56,7 +56,8 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin): 'display_metric' ) list_filter = ( - ActiveOrderListFilter, IgnoreOrderListFilter, BilledOrderListFilter, 'service' + ActiveOrderListFilter, IgnoreOrderListFilter, BilledOrderListFilter, 'account__type', + 'service', ) default_changelist_filters = ( ('ignore', '0'), diff --git a/orchestra/contrib/systemusers/actions.py b/orchestra/contrib/systemusers/actions.py index f896e797..b37780c3 100644 --- a/orchestra/contrib/systemusers/actions.py +++ b/orchestra/contrib/systemusers/actions.py @@ -47,7 +47,7 @@ def set_permission(modeladmin, request, queryset): user.set_perm_perms) context = { 'action': verbose_action, - 'perms': verbose_permissions, + 'perms': verbose_permissions.lower(), 'to': os.path.join(user.set_perm_base_home, user.set_perm_home_extension), } msg = _("%(action)s %(perms)s permission to %(to)s") % context