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.py465
1 files changed, 0 insertions, 465 deletions
diff --git a/src/mailman/database/mailinglist.py b/src/mailman/database/mailinglist.py
deleted file mode 100644
index 447d4657a..000000000
--- a/src/mailman/database/mailinglist.py
+++ /dev/null
@@ -1,465 +0,0 @@
-# Copyright (C) 2006-2009 by the Free Software Foundation, Inc.
-#
-# This file is part of GNU Mailman.
-#
-# GNU Mailman is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option)
-# any later version.
-#
-# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-# more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
-
-"""Model for mailing lists."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'MailingList',
- ]
-
-
-import os
-import string
-
-from storm.locals import (
- And, Bool, DateTime, Float, Int, Pickle, Reference, Store, TimeDelta,
- Unicode)
-from urlparse import urljoin
-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.domain import IDomainManager
-from mailman.interfaces.mailinglist import (
- IAcceptableAlias, IAcceptableAliasSet, IMailingList, Personalization)
-from mailman.interfaces.mime import FilterType
-from mailman.utilities.filesystem import makedirs
-from mailman.utilities.string import expand
-
-
-SPACE = ' '
-UNDERSCORE = '_'
-
-
-
-class MailingList(Model):
- implements(IMailingList)
-
- id = Int(primary=True)
-
- # List identity
- list_name = Unicode()
- host_name = Unicode()
- list_id = Unicode()
- include_list_post_header = Bool()
- include_rfc2369_headers = Bool()
- # Attributes not directly modifiable via the web u/i
- created_at = DateTime()
- admin_member_chunksize = Int()
- # Attributes which are directly modifiable via the web u/i. The more
- # complicated attributes are currently stored as pickles, though that
- # will change as the schema and implementation is developed.
- next_request_id = Int()
- next_digest_number = Int()
- digest_last_sent_at = DateTime()
- volume = Int()
- last_post_time = DateTime()
- # Implicit destination.
- acceptable_aliases_id = Int()
- acceptable_alias = Reference(acceptable_aliases_id, 'AcceptableAlias.id')
- # Attributes which are directly modifiable via the web u/i. The more
- # complicated attributes are currently stored as pickles, though that
- # will change as the schema and implementation is developed.
- accept_these_nonmembers = Pickle()
- admin_immed_notify = Bool()
- admin_notify_mchanges = Bool()
- administrivia = Bool()
- advertised = Bool()
- anonymous_list = Bool()
- archive = Bool()
- archive_private = Bool()
- archive_volume_frequency = Int()
- # Automatic responses.
- autoresponse_grace_period = TimeDelta()
- autorespond_owner = Enum()
- autoresponse_owner_text = Unicode()
- autorespond_postings = Enum()
- 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()
- bounce_matching_headers = Unicode()
- bounce_notify_owner_on_disable = Bool()
- bounce_notify_owner_on_removal = Bool()
- bounce_processing = Bool()
- bounce_score_threshold = Int()
- bounce_unrecognized_goes_to_list_owner = Bool()
- bounce_you_are_disabled_warnings = Int()
- bounce_you_are_disabled_warnings_interval = TimeDelta()
- default_member_moderation = Bool()
- description = Unicode()
- digest_footer = Unicode()
- digest_header = Unicode()
- digest_is_default = Bool()
- digest_send_periodic = Bool()
- digest_size_threshold = Float()
- digest_volume_frequency = Enum()
- digestable = Bool()
- discard_these_nonmembers = Pickle()
- emergency = Bool()
- encode_ascii_prefixes = Bool()
- first_strip_reply_to = Bool()
- forward_auto_discards = Bool()
- gateway_to_mail = Bool()
- gateway_to_news = Bool()
- generic_nonmember_action = Int()
- goodbye_msg = Unicode()
- header_matches = Pickle()
- hold_these_nonmembers = Pickle()
- info = Unicode()
- linked_newsgroup = Unicode()
- max_days_to_hold = Int()
- max_message_size = Int()
- max_num_recipients = Int()
- member_moderation_action = Enum()
- member_moderation_notice = Unicode()
- mime_is_default_digest = Bool()
- moderator_password = Unicode()
- msg_footer = Unicode()
- msg_header = Unicode()
- new_member_options = Int()
- news_moderation = Enum()
- news_prefix_subject_too = Bool()
- nntp_host = Unicode()
- nondigestable = Bool()
- nonmember_rejection_notice = Unicode()
- obscure_addresses = Bool()
- personalize = Enum()
- pipeline = Unicode()
- post_id = Int()
- _preferred_language = Unicode(name='preferred_language')
- private_roster = Bool()
- real_name = Unicode()
- reject_these_nonmembers = Pickle()
- reply_goes_to_list = Enum()
- reply_to_address = Unicode()
- require_explicit_destination = Bool()
- respond_to_post_requests = Bool()
- scrub_nondigest = Bool()
- send_goodbye_msg = Bool()
- send_reminders = Bool()
- send_welcome_msg = Bool()
- start_chain = Unicode()
- subject_prefix = Unicode()
- subscribe_auto_approval = Pickle()
- subscribe_policy = Int()
- topics = Pickle()
- topics_bodylines_limit = Int()
- topics_enabled = Bool()
- unsubscribe_policy = Int()
- welcome_msg = Unicode()
-
- def __init__(self, fqdn_listname):
- super(MailingList, self).__init__()
- listname, at, hostname = fqdn_listname.partition('@')
- assert hostname, 'Bad list name: {0}'.format(fqdn_listname)
- self.list_name = listname
- self.host_name = hostname
- # For the pending database
- self.next_request_id = 1
- self._restore()
- self.personalization = Personalization.none
- self.real_name = string.capwords(
- SPACE.join(listname.split(UNDERSCORE)))
- makedirs(self.data_path)
-
- # XXX FIXME
- def _restore(self):
- self.owners = roster.OwnerRoster(self)
- self.moderators = roster.ModeratorRoster(self)
- self.administrators = roster.AdministratorRoster(self)
- self.members = roster.MemberRoster(self)
- self.regular_members = roster.RegularMemberRoster(self)
- self.digest_members = roster.DigestMemberRoster(self)
- self.subscribers = roster.Subscribers(self)
-
- def __repr__(self):
- return '<mailing list "{0}" at {1:#x}>'.format(
- self.fqdn_listname, id(self))
-
- @property
- def fqdn_listname(self):
- """See `IMailingList`."""
- return '{0}@{1}'.format(self.list_name, self.host_name)
-
- @property
- def web_host(self):
- """See `IMailingList`."""
- return IDomainManager(config)[self.host_name]
-
- def script_url(self, target, context=None):
- """See `IMailingList`."""
- # Find the domain for this mailing list.
- domain = IDomainManager(config)[self.host_name]
- # XXX Handle the case for when context is not None; those would be
- # relative URLs.
- return urljoin(domain.base_url, target + '/' + self.fqdn_listname)
-
- @property
- def data_path(self):
- """See `IMailingList`."""
- return os.path.join(config.LIST_DATA_DIR, self.fqdn_listname)
-
- # IMailingListAddresses
-
- @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))
- return '{0}@{1}'.format(local_part, self.host_name)
-
- @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
- except AttributeError:
- self._preferred_language = language
-
- def send_one_last_digest_to(self, address, delivery_mode):
- """See `IMailingList`."""
- digest = OneLastDigest(self, address, delivery_mode)
- Store.of(self).add(digest)
-
- @property
- def last_digest_recipients(self):
- """See `IMailingList`."""
- results = Store.of(self).find(
- OneLastDigest,
- OneLastDigest.mailing_list == self)
- recipients = [(digest.address, digest.delivery_mode)
- for digest in results]
- results.remove()
- return recipients
-
- @property
- def filter_types(self):
- """See `IMailingList`."""
- 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
-
- @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)
-
- @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 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)
-
-
-
-class AcceptableAlias(Model):
- implements(IAcceptableAlias)
-
- id = Int(primary=True)
-
- mailing_list_id = Int()
- mailing_list = Reference(mailing_list_id, MailingList.id)
-
- alias = Unicode()
-
- 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