diff --git a/modoboa/extensions/amavis/forms.py b/modoboa/extensions/amavis/forms.py index 315c47e99..feea430d8 100644 --- a/modoboa/extensions/amavis/forms.py +++ b/modoboa/extensions/amavis/forms.py @@ -8,6 +8,7 @@ from django.utils.html import conditional_escape from django.utils.encoding import force_unicode from django.utils.safestring import mark_safe + class CustomRadioInput(RadioInput): def __unicode__(self): if 'id' in self.attrs: @@ -17,6 +18,7 @@ class CustomRadioInput(RadioInput): choice_label = conditional_escape(force_unicode(self.choice_label)) return mark_safe(u'' % (label_for, self.tag(), choice_label)) + class InlineRadioRenderer(RadioSelect.renderer): def __iter__(self): for i, choice in enumerate(self.choices): @@ -25,28 +27,30 @@ class InlineRadioRenderer(RadioSelect.renderer): def render(self): return mark_safe(u'\n'.join([u'%s\n' % force_unicode(w) for w in self])) + class InlineRadioSelect(RadioSelect): renderer = InlineRadioRenderer + class DomainPolicyForm(forms.ModelForm): spam_subject_tag2_act = forms.BooleanField() class Meta: model = Policy - fields = ('bypass_virus_checks', 'bypass_spam_checks', + fields = ('bypass_virus_checks', 'bypass_spam_checks', 'spam_tag2_level', 'spam_subject_tag2', 'spam_kill_level', 'bypass_banned_checks') widgets = { - 'bypass_virus_checks' : InlineRadioSelect(), - 'bypass_spam_checks' : InlineRadioSelect(), - 'spam_tag2_level' : forms.TextInput(attrs={'class' : 'span1'}), - 'spam_kill_level' : forms.TextInput(attrs={'class' : 'span1'}), - 'spam_subject_tag2' : forms.TextInput(attrs={'class' : 'span2'}), - 'bypass_banned_checks' : InlineRadioSelect(), + 'bypass_virus_checks': InlineRadioSelect(), + 'bypass_spam_checks': InlineRadioSelect(), + 'spam_tag2_level': forms.TextInput(attrs={'class': 'span1'}), + 'spam_kill_level': forms.TextInput(attrs={'class': 'span1'}), + 'spam_subject_tag2': forms.TextInput(attrs={'class': 'span2'}), + 'bypass_banned_checks': InlineRadioSelect(), } def __init__(self, *args, **kwargs): - if kwargs.has_key("instance"): + if "instance" in kwargs: self.domain = kwargs["instance"] try: policy = Users.objects.get(email="@%s" % self.domain.name).policy @@ -56,7 +60,7 @@ class DomainPolicyForm(forms.ModelForm): super(DomainPolicyForm, self).__init__(*args, **kwargs) for f in self.fields.keys(): self.fields[f].required = False - + def save(self, user, commit=True): p = super(DomainPolicyForm, self).save(commit=False) for f in ['bypass_spam_checks', 'bypass_virus_checks', 'bypass_banned_checks']: diff --git a/modoboa/extensions/amavis/lib.py b/modoboa/extensions/amavis/lib.py index 56288b3f1..1d3774ca9 100644 --- a/modoboa/extensions/amavis/lib.py +++ b/modoboa/extensions/amavis/lib.py @@ -11,6 +11,7 @@ from modoboa.lib import parameters from modoboa.lib.exceptions import ModoboaException from models import Msgrcpt + def selfservice(ssfunc=None): """Decorator used to expose views to the 'self-service' feature @@ -34,6 +35,7 @@ def selfservice(ssfunc=None): return wrapped_f return decorator + class AMrelease(object): def __init__(self): mode = parameters.get_admin("AM_PDP_MODE") diff --git a/modoboa/extensions/amavis/models.py b/modoboa/extensions/amavis/models.py index bd50dafd6..bda2a14ef 100644 --- a/modoboa/extensions/amavis/models.py +++ b/modoboa/extensions/amavis/models.py @@ -12,23 +12,28 @@ from django.db import models from django.utils.translation import ugettext as _, ugettext_lazy + class Maddr(models.Model): partition_tag = models.IntegerField(unique=True, null=True, blank=True) id = models.BigIntegerField(primary_key=True) email = models.CharField(unique=True, max_length=255) domain = models.CharField(max_length=765) + class Meta: db_table = u'maddr' managed = False + class Mailaddr(models.Model): id = models.IntegerField(primary_key=True) priority = models.IntegerField() email = models.CharField(unique=True, max_length=255) + class Meta: db_table = u'mailaddr' managed = False + class Msgs(models.Model): partition_tag = models.IntegerField(null=True, blank=True) mail_id = models.CharField(max_length=12, primary_key=True) @@ -50,11 +55,13 @@ class Msgs(models.Model): from_addr = models.CharField(max_length=765, blank=True) subject = models.CharField(max_length=765, blank=True) host = models.CharField(max_length=765) + class Meta: db_table = u'msgs' managed = False unique_together = ('partition_tag', 'mail_id') + class Msgrcpt(models.Model): partition_tag = models.IntegerField(null=True, blank=True) mail = models.ForeignKey(Msgs, primary_key=True) @@ -68,11 +75,13 @@ class Msgrcpt(models.Model): wl = models.CharField(max_length=3, blank=True) bspam_level = models.FloatField(null=True, blank=True) smtp_resp = models.CharField(max_length=765, blank=True) + class Meta: db_table = u'msgrcpt' managed = False unique_together = ("partition_tag", "mail", "rseqnum") + class Policy(models.Model): policy_name = models.CharField(max_length=96, blank=True) virus_lover = models.CharField(max_length=3, blank=True, null=True) @@ -82,24 +91,24 @@ class Policy(models.Model): bad_header_lover = models.CharField(max_length=3, blank=True, null=True) bypass_virus_checks = models.CharField( ugettext_lazy("Virus filter"), default='', null=True, - choices=(('N', ugettext_lazy('yes')), - ('Y', ugettext_lazy('no')), + choices=(('N', ugettext_lazy('yes')), + ('Y', ugettext_lazy('no')), ('', ugettext_lazy('default'))), max_length=3, help_text=ugettext_lazy("Bypass virus checks or not. Choose 'default' to use global settings.") ) bypass_spam_checks = models.CharField( ugettext_lazy("Spam filter"), default='', null=True, - choices=(('N', ugettext_lazy('yes')), - ('Y', ugettext_lazy('no')), + choices=(('N', ugettext_lazy('yes')), + ('Y', ugettext_lazy('no')), ('', ugettext_lazy('default'))), max_length=3, help_text=ugettext_lazy("Bypass spam checks or not. Choose 'default' to use global settings.") ) bypass_banned_checks = models.CharField( ugettext_lazy("Banned filter"), default='', null=True, - choices=(('N', ugettext_lazy('yes')), - ('Y', ugettext_lazy('no')), + choices=(('N', ugettext_lazy('yes')), + ('Y', ugettext_lazy('no')), ('', ugettext_lazy('default'))), max_length=3, help_text=ugettext_lazy("Bypass banned checks or not. Choose 'default' to use global settings.") @@ -148,31 +157,37 @@ class Policy(models.Model): db_table = u'policy' managed = False + class Quarantine(models.Model): partition_tag = models.IntegerField(null=True, blank=True) mail = models.ForeignKey(Msgs, primary_key=True) chunk_ind = models.IntegerField() mail_text = models.TextField() + class Meta: db_table = u'quarantine' managed = False ordering = ["-mail__time_num"] unique_together = ("partition_tag", "mail", "chunk_ind") + class Users(models.Model): id = models.AutoField(primary_key=True) priority = models.IntegerField() policy = models.ForeignKey(Policy) email = models.CharField(unique=True, max_length=255) fullname = models.CharField(max_length=765, blank=True) + class Meta: db_table = u'users' managed = False + class Wblist(models.Model): rid = models.IntegerField(primary_key=True) sid = models.IntegerField(primary_key=True) wb = models.CharField(max_length=30) + class Meta: db_table = u'wblist' managed = False diff --git a/modoboa/extensions/amavis/sql_listing.py b/modoboa/extensions/amavis/sql_listing.py index a9c635fa2..9724ae651 100644 --- a/modoboa/extensions/amavis/sql_listing.py +++ b/modoboa/extensions/amavis/sql_listing.py @@ -10,6 +10,7 @@ from modoboa.lib.emailutils import * from modoboa.lib.dbutils import db_type from models import * + class Qtable(tables.Table): tableid = "emails" styles = "table-condensed" @@ -31,13 +32,14 @@ class Qtable(tables.Table): def parse_date(self, value): return datetime.fromtimestamp(value) + class SQLconnector(MBconnector): orders = { - "from" : "mail__from_addr", - "subject" : "mail__subject", - "date" : "mail__time_num" + "from": "mail__from_addr", + "subject": "mail__subject", + "date": "mail__time_num" } - + def __init__(self, mail_ids=None, filter=None): self.count = None self.mail_ids = mail_ids @@ -51,7 +53,7 @@ class SQLconnector(MBconnector): if self.filter: filter &= self.filter self.messages = Quarantine.objects.filter(filter) - if kwargs.has_key("order"): + if "order" in kwargs: totranslate = kwargs["order"][1:] sign = kwargs["order"][:1] if sign == " ": @@ -66,12 +68,12 @@ class SQLconnector(MBconnector): emails = [] for qm in messages: for rcpt in qm.mail.msgrcpt_set.all(): - m = {"from" : qm.mail.from_addr, - "to" : rcpt.rid.email, - "subject" : qm.mail.subject, - "mailid" : qm.mail_id, - "date" : qm.mail.time_num, - "type" : rcpt.content} + m = {"from": qm.mail.from_addr, + "to": rcpt.rid.email, + "subject": qm.mail.subject, + "mailid": qm.mail_id, + "date": qm.mail.time_num, + "type": rcpt.content} if rcpt.rs == '': m["class"] = "unseen" elif rcpt.rs == 'R': @@ -100,7 +102,7 @@ class SQLWrapper(object): q = Q(rs='p') else: q = ~Q(rs='D') - + if request.user.group == 'SimpleUsers': q &= Q(rid__email=request.user.email) else: @@ -126,7 +128,7 @@ class SQLWrapper(object): def get_pending_requests(self, user): """Return the number of current pending requests - + :param user: a ``User`` instance """ rq = Q(rs='p') @@ -139,16 +141,17 @@ class SQLWrapper(object): rq &= doms_q return Msgrcpt.objects.filter(rq).count() - def get_mail_content(self, mailid): + def get_mail_content(self, mailid): return Quarantine.objects.filter(mail=mailid) + class PgWrapper(SQLWrapper): """The postgres wrapper Make use of ``QuerySet.extra`` and postgres ``convert_from`` function to let the quarantine manager work as expected ! """ - + def get_mails(self, request, rcptfilter=None): if request.GET.get("viewrequests", None) == "1": q = Q(rs='p') @@ -171,43 +174,43 @@ class PgWrapper(SQLWrapper): def get_recipient_message(self, address, mailid): qset = Msgrcpt.objects.filter(mail=mailid).extra( - where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') = '%s'" % address], + where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') = '%s'" % address], tables=['maddr'] ) return qset.all()[0] def get_recipient_messages(self, address, mailids): return Msgrcpt.objects.filter(mail__in=mailids).extra( - where=["U0.rid=maddr.id", "convert_from(maddr.email, 'UTF8') = '%s'" % address], + where=["U0.rid=maddr.id", "convert_from(maddr.email, 'UTF8') = '%s'" % address], tables=['maddr'] ) def get_domains_pending_requests(self, domains): regexp = "(%s)" % '|'.join(map(lambda dom: dom.name, domains)) return Msgrcpt.objects.filter(rs='p').extra( - where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') ~ '%s'" % regexp], + where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') ~ '%s'" % regexp], tables=['maddr'] ) def get_pending_requests(self, user): - rq = Q(rs='p') - if not user.is_superuser: - doms = user.get_domains() - if not doms.count(): - return 0 - regexp = "(%s)" % '|'.join(map(lambda dom: dom.name, doms)) - return Msgrcpt.objects.filter(rq).extra( - where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') ~ '%s'" % (regexp,)], - tables=['maddr'] - ).count() - return len(Msgrcpt.objects.filter(rq)) - + rq = Q(rs='p') + if not user.is_superuser: + doms = user.get_domains() + if not doms.count(): + return 0 + regexp = "(%s)" % '|'.join(map(lambda dom: dom.name, doms)) + return Msgrcpt.objects.filter(rq).extra( + where=["msgrcpt.rid=maddr.id", "convert_from(maddr.email, 'UTF8') ~ '%s'" % (regexp,)], + tables=['maddr'] + ).count() + return len(Msgrcpt.objects.filter(rq)) def get_mail_content(self, mailid): return Quarantine.objects.filter(mail=mailid).extra( - select={'mail_text' : "convert_from(mail_text, 'UTF8')"} + select={'mail_text': "convert_from(mail_text, 'UTF8')"} ) + def get_wrapper(): """Return the appropriate *Wrapper class @@ -217,6 +220,7 @@ def get_wrapper(): return PgWrapper() return SQLWrapper() + class SQLlisting(EmailListing): tpl = "amavis/index.html" tbltype = Qtable @@ -230,16 +234,16 @@ class SQLlisting(EmailListing): else: Qtable.cols_order = ['type', 'rstatus', 'to', 'from_', 'subject', 'time'] self.mbc = SQLconnector(msgs, filter) - super(SQLlisting, self).__init__(**kwargs) + class SQLemail(Email): def __init__(self, msg, *args, **kwargs): super(SQLemail, self).__init__(msg, *args, **kwargs) fields = ["From", "To", "Cc", "Date", "Subject"] for f in fields: label = f - self.headers += [{"name" : label, "value" : self.get_header(msg, f)}] + self.headers += [{"name": label, "value": self.get_header(msg, f)}] try: label = re.sub("-", "_", label) setattr(self, label, msg[f]) @@ -255,18 +259,15 @@ class SQLemail(Email): # Workaround for amavis <= 2.8.0 :p self.qtype = "BAD HEADER SECTION" self.qreason = qreason[19:] - def get_header(self, msg, name): - if msg.has_key(name): - return msg[name] - name = name.upper() - if msg.has_key(name): - return msg[name] + for k in [name, name.upper()]: + if k in msg: + return msg[k] return "" def render_headers(self, **kwargs): return render_to_string("amavis/mailheaders.html", { - "qtype" : self.qtype, "qreason" : self.qreason, - "headers" : self.headers, + "qtype": self.qtype, "qreason": self.qreason, + "headers": self.headers, }) diff --git a/modoboa/extensions/amavis/templatetags/amextras.py b/modoboa/extensions/amavis/templatetags/amextras.py index d36ff6fcd..f4989034f 100644 --- a/modoboa/extensions/amavis/templatetags/amextras.py +++ b/modoboa/extensions/amavis/templatetags/amextras.py @@ -15,7 +15,7 @@ def viewm_menu(user, mail_id, rcpt): {"name" : "release", "img" : "icon-white icon-ok", "class" : "btn-success", - "url" : reverse(amavis.views.release, args=[mail_id]) \ + "url" : reverse(amavis.views.release, args=[mail_id]) + ("?rcpt=%s" % rcpt if rcpt else ""), "label" : _("Release")}, {"name" : "delete", diff --git a/modoboa/extensions/amavis/views.py b/modoboa/extensions/amavis/views.py index a1579f79d..5622c98e6 100644 --- a/modoboa/extensions/amavis/views.py +++ b/modoboa/extensions/amavis/views.py @@ -17,23 +17,26 @@ from templatetags.amextras import * from modoboa.lib.email_listing import parse_search_parameters from sql_listing import * + def __get_current_url(request): - if request.session.has_key("page"): + if "page" in request.session: res = "listing?page=%s" % request.session["page"] else: res = "" - params = "&".join(map(lambda p: "%s=%s" % (p, request.session[p]), + params = "&".join(map(lambda p: "%s=%s" % (p, request.session[p]), filter(request.session.has_key, ["criteria", "pattern"]))) if params != "": res += "?%s" % (params) return res + def empty_quarantine(request): content = "