diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py index de5da9e3..80482abd 100644 --- a/orchestra/contrib/mailboxes/admin.py +++ b/orchestra/contrib/mailboxes/admin.py @@ -17,6 +17,7 @@ from .actions import SendMailboxEmail from .filters import HasMailboxListFilter, HasForwardListFilter, HasAddressListFilter from .forms import MailboxCreationForm, MailboxChangeForm, AddressForm from .models import Mailbox, Address, Autoresponse +from .widgets import OpenCustomFilteringOnSelect class AutoresponseInline(admin.StackedInline): @@ -81,12 +82,17 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo self.actions = () return super(MailboxAdmin, self).get_actions(request) + def formfield_for_dbfield(self, db_field, **kwargs): + if db_field.name == 'filtering': + kwargs['widget'] = OpenCustomFilteringOnSelect() + return super(MailboxAdmin, self).formfield_for_dbfield(db_field, **kwargs) + def get_fieldsets(self, request, obj=None): fieldsets = super(MailboxAdmin, self).get_fieldsets(request, obj) if obj and obj.filtering == obj.CUSTOM: # not collapsed filtering when exists fieldsets = copy.deepcopy(fieldsets) - fieldsets[1][1]['classes'] = fieldsets[0][1]['fields'] + ('open',) + fieldsets[1][1]['classes'] = fieldsets[0][1]['fields'] + ('collapse', 'open',) elif '_to_field' in parse_qs(request.META['QUERY_STRING']): # remove address from popup fieldsets = list(copy.deepcopy(fieldsets)) diff --git a/orchestra/contrib/mailboxes/backends.py b/orchestra/contrib/mailboxes/backends.py index bf39d265..c9b1dcd2 100644 --- a/orchestra/contrib/mailboxes/backends.py +++ b/orchestra/contrib/mailboxes/backends.py @@ -1,4 +1,5 @@ import logging +import re import textwrap from django.core.exceptions import ObjectDoesNotExist @@ -19,11 +20,13 @@ from .models import Address logger = logging.getLogger(__name__) -class FilteringMixin(object): +class SieveFilteringMixin(object): def generate_filter(self, mailbox, context): name, content = mailbox.get_filtering() - if name == 'REDIRECT': - self.append("doveadm mailbox create -u %(user)s Spam" % context) + for box in re.findall(r'fileinto\s+"([^"]+)"', content): + context['box'] = box + # TODO create mailbox without doveadm (not always installed) + self.append("doveadm mailbox create -u %(user)s %(box)s" % context) context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context if content: context['filtering'] = ('# %(banner)s\n' + filtering) % context @@ -33,7 +36,7 @@ class FilteringMixin(object): self.append("echo '' > %(filtering_path)s" % context) -class UNIXUserMaildirBackend(FilteringMixin, ServiceController): +class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController): """ Assumes that all system users on this servers all mail accounts. If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes @@ -94,7 +97,7 @@ class UNIXUserMaildirBackend(FilteringMixin, ServiceController): return replace(context, "'", '"') -class DovecotPostfixPasswdVirtualUserBackend(FilteringMixin, ServiceController): +class DovecotPostfixPasswdVirtualUserBackend(SieveFilteringMixin, ServiceController): """ WARNING: This backends is not fully implemented """ diff --git a/orchestra/contrib/mailboxes/settings.py b/orchestra/contrib/mailboxes/settings.py index a315719c..91d977e0 100644 --- a/orchestra/contrib/mailboxes/settings.py +++ b/orchestra/contrib/mailboxes/settings.py @@ -17,14 +17,14 @@ MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', 'domains.Domain', MAILBOXES_HOME = Setting('MAILBOXES_HOME', - '/home/%(name)s/', + '/home/%(name)s', help_text="Available fromat names: %s" % ', '.join(_names), validators=[Setting.string_format_validator(_names)], ) MAILBOXES_SIEVE_PATH = Setting('MAILBOXES_SIEVE_PATH', - os.path.join(MAILBOXES_HOME, 'Maildir/sieve/orchestra.sieve'), + os.path.join('%(home)s/Maildir/sieve/orchestra.sieve'), help_text="Available fromat names: %s" % ', '.join(_names), validators=[Setting.string_format_validator(_backend_names)], ) diff --git a/orchestra/contrib/mailboxes/widgets.py b/orchestra/contrib/mailboxes/widgets.py new file mode 100644 index 00000000..ad92adc8 --- /dev/null +++ b/orchestra/contrib/mailboxes/widgets.py @@ -0,0 +1,33 @@ +import textwrap + +from django import forms + + +class OpenCustomFilteringOnSelect(forms.Select): + def __init__(self, *args, **kwargs): + collapse = self.get_dynamic_collapse() + attrs = kwargs.get('attrs', {}) + attrs.update({ + 'onClick': collapse, + 'onChange': collapse, + }) + attrs.update(kwargs.get('attrs', {})) + kwargs['attrs'] = attrs + super(OpenCustomFilteringOnSelect, self).__init__(*args, **kwargs) + + def get_dynamic_collapse(self): + return textwrap.dedent("""\ + value = this.options[this.selectedIndex].value; + fieldset = $(this).closest("fieldset"); + fieldset = $(".collapse"); + if ( value == 'CUSTOM' ) { + if (fieldset.hasClass("collapsed")) { + fieldset.removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); + } + } else { + if (! $(this).closest("fieldset").hasClass("collapsed")) { + fieldset.addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); + } + } + """ + ) diff --git a/orchestra/forms/options.py b/orchestra/forms/options.py index ed908b5e..e81e68da 100644 --- a/orchestra/forms/options.py +++ b/orchestra/forms/options.py @@ -87,4 +87,3 @@ class ReadOnlyFormMixin(object): if hasattr(self, 'instance'): original = getattr(self.instance, name, original) field.widget.original = original -