------------------------------------------------------------
revno: 6639
committer: Barry Warsaw <[EMAIL PROTECTED]>
branch nick: domains
timestamp: Sat 2008-09-20 00:33:07 -0400
message:
Support for proper domains by interface. Add a test and update modules as
necessary. Finally delete DEFAULT_EMAIL_HOST and DEFAULT_URL_HOST. Now
add_domain() must be called in the confirmation file for every domain.
add_domain() itself is now pretty much just a proxy for the Domain
constructor.
Add stop() as an alias for pdb.set_trace() to the documentation doctest globs.
added:
mailman/docs/domains.txt
mailman/domain.py
modified:
mailman/Cgi/create.py
mailman/Defaults.py
mailman/archiving/mhonarc.py
mailman/archiving/pipermail.py
mailman/archiving/prototype.py
mailman/configuration.py
mailman/interfaces/domain.py
mailman/testing/testing.cfg.in
mailman/tests/test_documentation.py
=== modified file 'mailman/Cgi/create.py'
--- a/mailman/Cgi/create.py 2008-02-08 04:01:48 +0000
+++ b/mailman/Cgi/create.py 2008-09-20 04:33:07 +0000
@@ -151,8 +151,12 @@
# Make sure the url host name matches one of our virtual domains. Then
# calculate the list's posting address.
url_host = Utils.get_request_domain()
- email_host = config.get_email_host(url_host)
- if not email_host:
+ # Find the IDomain matching this url_host if there is one.
+ for email_host, domain in config.domains:
+ if domain.url_host == url_host:
+ email_host = domain.email_host
+ break
+ else:
safehostname = Utils.websafe(url_host)
request_creation(doc, cgidata,
_('Unknown virtual host: $safehostname'))
=== modified file 'mailman/Defaults.py'
--- a/mailman/Defaults.py 2008-07-10 02:35:44 +0000
+++ b/mailman/Defaults.py 2008-09-20 04:33:07 +0000
@@ -124,40 +124,6 @@
#####
-# Virtual domains
-#####
-
-# Mailman needs to know about at least one domain, called the 'site default
-# domain'. If you run only one domain with Mailman, this will generally be
-# calculated automatically when you configured Mailman. You can always change
-# this in your mailman.cfg file. You can also add additional virtual domains
-# in your mailman.cfg file to enable multiple virtual domains. Every mailing
-# list will be situated in exactly one virtual domain.
-#
-# For Mailman's purposes, a virtual domain associates an email host name with
-# a web host name. These may be the same, but often they are different, and
-# the list is always referred to by its fully-qualified posting address. For
-# example, if you created 'mylist' in the example.com domain, people can post
-# to your list via '[EMAIL PROTECTED]'. They may refer to the web pages via
-# 'www.example.com'. So your email host name is 'example.com' and your web
-# host name is 'www.example.com'.
-#
-# To add a virtual domain, put a call to add_domain(email_host, url_host) in
-# your mailman.cfg file. If no add_domain() calls are found, Mailman will
-# automatically add a virtual domain for the following defaults. However if
-# you explicit add domains, you will need to add these defaults as well.
-#
-# These defaults will be filled in by configure.
-DEFAULT_EMAIL_HOST = '@MAILHOST@'
-DEFAULT_URL_HOST = '@URLHOST@'
-
-# Note that you will want to run bin/fix_url.py to change the domain of an
-# existing list. bin/fix_url.py must be run within the bin/withlist script,
-# like so: bin/withlist -l -r bin/fix_url.py <listname>
-
-
-
-#####
# Spam avoidance defaults
#####
=== modified file 'mailman/archiving/mhonarc.py'
--- a/mailman/archiving/mhonarc.py 2008-07-10 02:35:44 +0000
+++ b/mailman/archiving/mhonarc.py 2008-09-20 04:33:07 +0000
@@ -52,7 +52,7 @@
def list_url(mlist):
"""See `IArchiver`."""
# XXX What about private MHonArc archives?
- web_host = config.domains.get(mlist.host_name, mlist.host_name)
+ web_host = config.domains[mlist.host_name].url_host
return Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
listname=mlist.fqdn_listname,
hostname=web_host,
=== modified file 'mailman/archiving/pipermail.py'
--- a/mailman/archiving/pipermail.py 2008-07-05 15:06:37 +0000
+++ b/mailman/archiving/pipermail.py 2008-09-20 04:33:07 +0000
@@ -59,7 +59,15 @@
def adapt_mailing_list_for_pipermail(iface, obj):
- """Adapt IMailingLists to IPipermailMailingList."""
+ """Adapt `IMailingLists` to `IPipermailMailingList`.
+
+ :param iface: The interface to adapt to.
+ :type iface: `zope.interface.Interface`
+ :param obj: The object being adapted.
+ :type obj: any object
+ :return: An `IPipermailMailingList` instance if adaptation succeeded or
+ None if it didn't.
+ """
if IMailingList.providedBy(obj) and iface is IPipermailMailingList:
return PipermailMailingListAdapter(obj)
return None
@@ -82,7 +90,7 @@
if mlist.archive_private:
url = mlist.script_url('private') + '/index.html'
else:
- web_host = config.domains.get(mlist.host_name, mlist.host_name)
+ web_host = config.domains[mlist.host_name].url_host
url = Template(config.PUBLIC_ARCHIVE_URL).safe_substitute(
listname=mlist.fqdn_listname,
hostname=web_host,
=== modified file 'mailman/archiving/prototype.py'
--- a/mailman/archiving/prototype.py 2008-07-10 02:35:44 +0000
+++ b/mailman/archiving/prototype.py 2008-09-20 04:33:07 +0000
@@ -49,8 +49,7 @@
@staticmethod
def list_url(mlist):
"""See `IArchiver`."""
- web_host = config.domains.get(mlist.host_name, mlist.host_name)
- return 'http://' + web_host
+ return config.domains[mlist.host_name].base_url
@staticmethod
def permalink(mlist, msg):
=== modified file 'mailman/configuration.py'
--- a/mailman/configuration.py 2008-07-05 15:06:37 +0000
+++ b/mailman/configuration.py 2008-09-20 04:33:07 +0000
@@ -24,6 +24,7 @@
from mailman import Defaults
from mailman import Errors
from mailman import version
+from mailman.domain import Domain
from mailman.languages import LanguageManager
SPACE = ' '
@@ -45,8 +46,7 @@
class Configuration(object):
def __init__(self):
- self.domains = {} # email host -> web host
- self._reverse = None
+ self.domains = {} # email host -> IDomain
self.qrunners = {}
self.qrunner_shortcuts = {}
self.QFILE_SCHEMA_VERSION = version.QFILE_SCHEMA_VERSION
@@ -150,10 +150,6 @@
del ns['add_qrunner']
del ns['del_qrunner']
self.__dict__.update(ns)
- # Add the default domain if there are no virtual domains currently
- # defined.
- if not self.domains:
- self.add_domain(self.DEFAULT_EMAIL_HOST, self.DEFAULT_URL_HOST)
# Enable all specified languages, and promote the language manager to
# a public attribute.
self.languages = self._languages
@@ -181,36 +177,25 @@
self.pipelines = {}
self.commands = {}
- def add_domain(self, email_host, url_host=None):
+ def add_domain(self, *args, **kws):
"""Add a virtual domain.
- :param email_host: The host name for the email interface.
- :param url_host: Optional host name for the web interface. If not
- given, the email host will be used.
+ See `Domain`.
"""
- if url_host is None:
- url_host = email_host
- if email_host in self.domains:
+ domain = Domain(*args, **kws)
+ if domain.email_host in self.domains:
raise Errors.BadDomainSpecificationError(
- 'Duplicate email host: %s' % email_host)
+ 'Duplicate email host: %s' % domain.email_host)
# Make sure there's only one mapping for the url_host
- if url_host in self.domains.values():
+ if domain.url_host in self.domains.values():
raise Errors.BadDomainSpecificationError(
- 'Duplicate url host: %s' % url_host)
+ 'Duplicate url host: %s' % domain.url_host)
# We'll do the reverse mappings on-demand. There shouldn't be too
# many virtual hosts that it will really matter that much.
- self.domains[email_host] = url_host
- # Invalidate the reverse mapping cache
- self._reverse = None
+ self.domains[domain.email_host] = domain
- # Given an email host name, the url host name can be looked up directly.
- # This does the reverse mapping.
- def get_email_host(self, url_host, default=None):
- if self._reverse is None:
- # XXX Can't use a generator comprehension until Python 2.4 is
- # minimum requirement.
- self._reverse = dict([(v, k) for k, v in self.domains.items()])
- return self._reverse.get(url_host, default)
+ # Proxy the docstring for the above method.
+ add_domain.__doc__ = Domain.__init__.__doc__
def add_qrunner(self, name, count=1):
"""Convenient interface for adding additional qrunners.
=== added file 'mailman/docs/domains.txt'
--- a/mailman/docs/domains.txt 1970-01-01 00:00:00 +0000
+++ b/mailman/docs/domains.txt 2008-09-20 04:33:07 +0000
@@ -0,0 +1,74 @@
+Domains
+=======
+
+Domains are how Mailman interacts with email host names and web host names.
+Generally, new domains are registered in the mailman.cfg configuration file by
+calling the add_domain() method.
+
+At a minimum, the email host name must be specified.
+
+ >>> from mailman.configuration import config
+ >>> config.add_domain('example.net')
+
+The domain object can be looked up by email host name.
+
+ >>> domain = config.domains['example.net']
+ >>> print domain.email_host
+ example.net
+
+The base url is calculated by default if not given.
+
+ >>> print domain.base_url
+ http://example.net
+
+There is no description by default.
+
+ >>> print domain.description
+ None
+
+By default, the contact address is the domain's postmaster.
+
+ >>> print domain.contact_address
+ [EMAIL PROTECTED]
+
+And the url_host is by default the same as the email host.
+
+ >>> print domain.url_host
+ example.net
+
+
+Full specification
+------------------
+
+The domain can also be much more fully defined.
+
+ >>> config.add_domain(
+ ... 'example.org', 'https://mail.example.org',
+ ... 'The example domain',
+ ... '[EMAIL PROTECTED]')
+
+ >>> domain = config.domains['example.org']
+ >>> print domain.email_host
+ example.org
+ >>> print domain.base_url
+ https://mail.example.org
+ >>> print domain.description
+ The example domain
+ >>> print domain.contact_address
+ [EMAIL PROTECTED]
+ >>> print domain.url_host
+ mail.example.org
+
+
+Confirmation tokens
+-------------------
+
+Confirmation tokens can be added to either the email confirmation address...
+
+ >>> print domain.confirm_address('xyz')
+ [EMAIL PROTECTED]
+
+...or the confirmation url.
+
+ >>> print domain.confirm_url('abc')
+ https://mail.example.org/confirm/abc
=== added file 'mailman/domain.py'
--- a/mailman/domain.py 1970-01-01 00:00:00 +0000
+++ b/mailman/domain.py 2008-09-20 04:33:07 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2008 by the Free Software Foundation, Inc.
+#
+# This program 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 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Domains."""
+
+__metaclass__ = type
+__all__ = [
+ 'Domain',
+ ]
+
+from urlparse import urljoin, urlparse
+from zope.interface import implements
+
+from mailman.interfaces.domain import IDomain
+
+
+
+class Domain:
+ """Domains."""
+
+ implements(IDomain)
+
+ def __init__(self, email_host, base_url=None, description=None,
+ contact_address=None):
+ """Create and register a domain.
+
+ :param email_host: The host name for the email interface.
+ :type email_host: string
+ :param base_url: The optional base url for the domain, including
+ scheme. If not given, it will be constructed from the
+ `email_host` using the http protocol.
+ :type base_url: string
+ :param description: An optional description of the domain.
+ :type description: string
+ :type contact_address: The email address to contact a human for this
+ domain. If not given, [EMAIL PROTECTED] will be used.
+ """
+ self.email_host = email_host
+ self.base_url = (base_url if base_url is not None else
+ 'http://' + email_host)
+ self.description = description
+ self.contact_address = (contact_address
+ if contact_address is not None
+ else 'postmaster@' + email_host)
+ self.url_host = urlparse(self.base_url).netloc
+
+ def confirm_address(self, token=''):
+ """See `IDomain`."""
+ return '[EMAIL PROTECTED]' % (token, self.email_host)
+
+ def confirm_url(self, token=''):
+ """See `IDomain`."""
+ return urljoin(self.base_url, 'confirm/' + token)
=== modified file 'mailman/interfaces/domain.py'
--- a/mailman/interfaces/domain.py 2008-02-08 04:01:48 +0000
+++ b/mailman/interfaces/domain.py 2008-09-20 04:33:07 +0000
@@ -24,30 +24,54 @@
class IDomain(Interface):
"""Interface representing domains."""
- domain_name = Attribute(
- """The domain's name, e.g. python.org.""")
+ email_host = Attribute(
+ """The host name for email for this domain.
+
+ :type: string
+ """)
+
+ url_host = Attribute(
+ """The host name for the web interface for this domain.
+
+ :type: string
+ """)
+
+ base_url = Attribute(
+ """The base url for the Mailman server at this domain.
+
+ The base url includes the scheme and host name.
+
+ :type: string
+ """)
description = Attribute(
"""The human readable description of the domain name.
- E.g. Python Dot Org or mail.python.org.
+ :type: string
""")
contact_address = Attribute(
"""The contact address for the human at this domain.
E.g. [EMAIL PROTECTED]
- """)
-
- base_url = Attribute(
- """The base url for the Mailman server at this domain.
-
- E.g. https://mail.python.org
+
+ :type: string
""")
def confirm_address(token=''):
- """The address used for various forms of email confirmation."""
+ """The address used for various forms of email confirmation.
+
+ :param token: The confirmation token to use in the email address.
+ :type token: string
+ :return: The email confirmation address.
+ :rtype: string
+ """
def confirm_url(token=''):
- """The url used for various forms of confirmation."""
+ """The url used for various forms of confirmation.
+ :param token: The confirmation token to use in the url.
+ :type token: string
+ :return: The confirmation url.
+ :rtype: string
+ """
=== modified file 'mailman/testing/testing.cfg.in'
--- a/mailman/testing/testing.cfg.in 2008-07-05 14:41:12 +0000
+++ b/mailman/testing/testing.cfg.in 2008-09-20 04:33:07 +0000
@@ -12,6 +12,6 @@
MAIL_ARCHIVE_BASEURL = 'http://go.mail-archive.dev/'
MAIL_ARCHIVE_RECIPIENT = '[EMAIL PROTECTED]'
-add_domain('example.com', 'www.example.com')
+add_domain('example.com', 'http://www.example.com')
# bin/testall will add additional runtime configuration variables here.
=== modified file 'mailman/tests/test_documentation.py'
--- a/mailman/tests/test_documentation.py 2008-07-06 14:27:05 +0000
+++ b/mailman/tests/test_documentation.py 2008-09-20 04:33:07 +0000
@@ -53,6 +53,14 @@
return message
+def stop():
+ """Call into pdb.set_trace()"""
+ # Do the import here so that you get the wacky special hacked pdb instead
+ # of Python's normal pdb.
+ import pdb
+ pdb.set_trace()
+
+
def setup(testobj):
"""Test setup."""
smtpd = SMTPServer()
@@ -64,6 +72,10 @@
testobj.globs['message_from_string'] = specialized_message_from_string
testobj.globs['commit'] = config.db.commit
testobj.globs['smtpd'] = smtpd
+ testobj.globs['stop'] = stop
+ # Stash the current state of the global domains away for restoration in
+ # the teardown.
+ testobj._domains = config.domains.copy()
@@ -71,6 +83,8 @@
"""Clear all persistent data at the end of a doctest."""
# Clear the database of all rows.
config.db._reset()
+ # Reset the global domains.
+ config.domains = testobj._domains
# Remove all but the default style.
for style in style_manager.styles:
if style.name <> 'default':
--
Primary development focus
https://code.launchpad.net/~mailman-coders/mailman/3.0
You are receiving this branch notification because you are subscribed to it.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org