summaryrefslogtreecommitdiff
path: root/src/mailman/database/mailinglist.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman/database/mailinglist.py')
-rw-r--r--src/mailman/database/mailinglist.py196
1 files changed, 167 insertions, 29 deletions
diff --git a/src/mailman/database/mailinglist.py b/src/mailman/database/mailinglist.py
index fa4af5ad0..22de044e3 100644
--- a/src/mailman/database/mailinglist.py
+++ b/src/mailman/database/mailinglist.py
@@ -22,6 +22,7 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'MailingList',
+ 'adapt_mailing_list_to_acceptable_alias_set',
]
@@ -37,10 +38,12 @@ from zope.interface import implements
from mailman.config import config
from mailman.database import roster
from mailman.database.digests import OneLastDigest
+from mailman.database.mime import ContentFilter
from mailman.database.model import Model
from mailman.database.types import Enum
from mailman.interfaces.mailinglist import (
- IAcceptableAlias, IMailingList, Personalization)
+ IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization)
+from mailman.interfaces.mime import FilterType
from mailman.utilities.filesystem import makedirs
from mailman.utilities.string import expand
@@ -92,6 +95,10 @@ class MailingList(Model):
autoresponse_postings_text = Unicode()
autorespond_requests = Enum()
autoresponse_request_text = Unicode()
+ # Content filters.
+ filter_content = Bool()
+ collapse_alternatives = Bool()
+ convert_html_to_plaintext = Bool()
# Bounces and bans.
ban_list = Pickle()
bounce_info_stale_after = TimeDelta()
@@ -103,8 +110,6 @@ class MailingList(Model):
bounce_unrecognized_goes_to_list_owner = Bool()
bounce_you_are_disabled_warnings = Int()
bounce_you_are_disabled_warnings_interval = TimeDelta()
- collapse_alternatives = Bool()
- convert_html_to_plaintext = Bool()
default_member_moderation = Bool()
description = Unicode()
digest_footer = Unicode()
@@ -117,10 +122,6 @@ class MailingList(Model):
discard_these_nonmembers = Pickle()
emergency = Bool()
encode_ascii_prefixes = Bool()
- filter_action = Int()
- filter_content = Bool()
- filter_filename_extensions = Pickle()
- filter_mime_types = Pickle()
first_strip_reply_to = Bool()
forward_auto_discards = Bool()
gateway_to_mail = Bool()
@@ -149,8 +150,6 @@ class MailingList(Model):
nondigestable = Bool()
nonmember_rejection_notice = Unicode()
obscure_addresses = Bool()
- pass_filename_extensions = Pickle()
- pass_mime_types = Pickle()
personalize = Enum()
pipeline = Unicode()
post_id = Int()
@@ -230,41 +229,51 @@ class MailingList(Model):
@property
def posting_address(self):
+ """See `IMailingList`."""
return self.fqdn_listname
@property
def no_reply_address(self):
+ """See `IMailingList`."""
return '{0}@{1}'.format(config.mailman.noreply_address, self.host_name)
@property
def owner_address(self):
+ """See `IMailingList`."""
return '{0}-owner@{1}'.format(self.list_name, self.host_name)
@property
def request_address(self):
+ """See `IMailingList`."""
return '{0}-request@{1}'.format(self.list_name, self.host_name)
@property
def bounces_address(self):
+ """See `IMailingList`."""
return '{0}-bounces@{1}'.format(self.list_name, self.host_name)
@property
def join_address(self):
+ """See `IMailingList`."""
return '{0}-join@{1}'.format(self.list_name, self.host_name)
@property
def leave_address(self):
+ """See `IMailingList`."""
return '{0}-leave@{1}'.format(self.list_name, self.host_name)
@property
def subscribe_address(self):
+ """See `IMailingList`."""
return '{0}-subscribe@{1}'.format(self.list_name, self.host_name)
@property
def unsubscribe_address(self):
+ """See `IMailingList`."""
return '{0}-unsubscribe@{1}'.format(self.list_name, self.host_name)
def confirm_address(self, cookie):
+ """See `IMailingList`."""
local_part = expand(config.mta.verp_confirm_format, dict(
address = '{0}-confirm'.format(self.list_name),
cookie = cookie))
@@ -272,10 +281,12 @@ class MailingList(Model):
@property
def preferred_language(self):
+ """See `IMailingList`."""
return config.languages[self._preferred_language]
@preferred_language.setter
def preferred_language(self, language):
+ """See `IMailingList`."""
# Accept both a language code and a `Language` instance.
try:
self._preferred_language = language.code
@@ -298,31 +309,109 @@ class MailingList(Model):
results.remove()
return recipients
- def clear_acceptable_aliases(self):
+ @property
+ def filter_types(self):
"""See `IMailingList`."""
- Store.of(self).find(
- AcceptableAlias,
- AcceptableAlias.mailing_list == self).remove()
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_mime))
+ for content_filter in results:
+ yield content_filter.filter_pattern
- def add_acceptable_alias(self, alias):
- if not (alias.startswith('^') or '@' in alias):
- raise ValueError(alias)
- alias = AcceptableAlias(self, alias.lower())
- Store.of(self).add(alias)
+ @filter_types.setter
+ def filter_types(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing MIME type filter patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_mime))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.filter_mime)
+ store.add(content_filter)
- def remove_acceptable_alias(self, alias):
- Store.of(self).find(
- AcceptableAlias,
- And(AcceptableAlias.mailing_list == self,
- AcceptableAlias.alias == alias.lower())).remove()
+ @property
+ def pass_types(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_mime))
+ for content_filter in results:
+ yield content_filter.filter_pattern
+
+ @pass_types.setter
+ def pass_types(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing MIME type pass patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_mime))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.pass_mime)
+ store.add(content_filter)
@property
- def acceptable_aliases(self):
- aliases = Store.of(self).find(
- AcceptableAlias,
- AcceptableAlias.mailing_list == self)
- for alias in aliases:
- yield alias.alias
+ def filter_extensions(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_extension))
+ for content_filter in results:
+ yield content_filter.filter_pattern
+
+ @filter_extensions.setter
+ def filter_extensions(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing file extensions filter patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.filter_extension))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.filter_extension)
+ store.add(content_filter)
+
+ @property
+ def pass_extensions(self):
+ """See `IMailingList`."""
+ results = Store.of(self).find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_extension))
+ for content_filter in results:
+ yield content_filter.pass_pattern
+
+ @pass_extensions.setter
+ def pass_extensions(self, sequence):
+ """See `IMailingList`."""
+ # First, delete all existing file extensions pass patterns.
+ store = Store.of(self)
+ results = store.find(
+ ContentFilter,
+ And(ContentFilter.mailing_list == self,
+ ContentFilter.filter_type == FilterType.pass_extension))
+ results.remove()
+ # Now add all the new filter types.
+ for mime_type in sequence:
+ content_filter = ContentFilter(
+ self, mime_type, FilterType.pass_extension)
+ store.add(content_filter)
@@ -339,3 +428,52 @@ class AcceptableAlias(Model):
def __init__(self, mailing_list, alias):
self.mailing_list = mailing_list
self.alias = alias
+
+
+class AcceptableAliasSet:
+ implements(IAcceptableAliasSet)
+
+ def __init__(self, mailing_list):
+ self._mailing_list = mailing_list
+
+ def clear(self):
+ """See `IAcceptableAliasSet`."""
+ Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ AcceptableAlias.mailing_list == self._mailing_list).remove()
+
+ def add(self, alias):
+ if not (alias.startswith('^') or '@' in alias):
+ raise ValueError(alias)
+ alias = AcceptableAlias(self._mailing_list, alias.lower())
+ Store.of(self._mailing_list).add(alias)
+
+ def remove(self, alias):
+ Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ And(AcceptableAlias.mailing_list == self._mailing_list,
+ AcceptableAlias.alias == alias.lower())).remove()
+
+ @property
+ def aliases(self):
+ aliases = Store.of(self._mailing_list).find(
+ AcceptableAlias,
+ AcceptableAlias.mailing_list == self._mailing_list)
+ for alias in aliases:
+ yield alias.alias
+
+
+
+def adapt_mailing_list_to_acceptable_alias_set(iface, obj):
+ """Adapt an `IMailingList` to an `IAcceptableAliasSet`.
+
+ :param iface: The interface to adapt to.
+ :type iface: `zope.interface.Interface`
+ :param obj: The object being adapted.
+ :type obj: `IMailingList`
+ :return: An `IAcceptableAliasSet` instance if adaptation succeeded or None
+ if it didn't.
+ """
+ return (AcceptableAliasSet(obj)
+ if IMailingList.providedBy(obj) and iface is IAcceptableAliasSet
+ else None)