------------------------------------------------------------
revno: 6542
committer: Barry Warsaw <[EMAIL PROTECTED]>
branch nick: 3.0
timestamp: Sun 2007-08-05 08:42:16 -0400
message:
Added a doctest for the Mailman.app.create module.
BadListNameError is gone. Use InvalidEmailAddress instead.
Move owner registration from bin/newlist to Mailman/app/create.py, but do not
verified owner email addresses here. Eventually we'll hook in the IRegistrar
stuff for unverified owner addresses.
IStyleManager.register() verifies that its registering an IStyle.
Added IStyleManager.unregister(), along with updated interfaces and doctests.
Clean up all styles except the default one in the system documentation test
harness.
added:
Mailman/docs/create.txt
modified:
Mailman/Cgi/create.py
Mailman/Errors.py
Mailman/app/create.py
Mailman/app/styles.py
Mailman/bin/newlist.py
Mailman/docs/styles.txt
Mailman/interfaces/styles.py
Mailman/tests/test_documentation.py
=== added file 'Mailman/docs/create.txt'
--- a/Mailman/docs/create.txt 1970-01-01 00:00:00 +0000
+++ b/Mailman/docs/create.txt 2007-08-05 12:42:16 +0000
@@ -0,0 +1,123 @@
+Application level list creation
+-------------------------------
+
+The low-level way to create a new mailing list is to use the IListManager
+interface. This interface simply adds the appropriate database entries to
+record the list's creation.
+
+There is a higher level interface for creating mailing lists which performs a
+few additional tasks such as:
+
+ * validating the list's posting address (which also serves as the list's
+ fully qualified name);
+ * ensuring that the list's domain is registered;
+ * applying all matching styles to the new list;
+ * creating and assigning list owners;
+ * notifying watchers of list creation;
+ * creating ancillary artifacts (such as the list's on-disk directory)
+
+ >>> from Mailman.app.create import create_list
+
+
+Posting address validation
+--------------------------
+
+If you try to use the higher-level interface to create a mailing list with a
+bogus posting address, you get an exception.
+
+ >>> create_list('not a valid address')
+ Traceback (most recent call last):
+ ...
+ InvalidEmailAddress: 'not a valid address'
+
+If the posting address is valid, but the domain has not been registered with
+Mailman yet, you get an exception.
+
+ >>> create_list('[EMAIL PROTECTED]')
+ Traceback (most recent call last):
+ ...
+ BadDomainSpecificationError: example.org
+
+
+Creating a list applies its styles
+----------------------------------
+
+Start by registering a test style.
+
+ >>> from zope.interface import implements
+ >>> from Mailman.interfaces import IStyle
+ >>> class TestStyle(object):
+ ... implements(IStyle)
+ ... name = 'test'
+ ... priority = 10
+ ... def apply(self, mailing_list):
+ ... # Just does something very simple.
+ ... mailing_list.msg_footer = u'test footer'
+ ... def match(self, mailing_list, styles):
+ ... # Applies to any test list
+ ... if 'test' in mailing_list.fqdn_listname:
+ ... styles.append(self)
+ >>> from Mailman.app.styles import style_manager
+ >>> style_manager.register(TestStyle())
+
+Using the higher level interface for creating a list, applies all matching
+list styles.
+
+ >>> mlist_1 = create_list('[EMAIL PROTECTED]')
+ >>> from Mailman.database import flush
+ >>> flush()
+ >>> mlist_1.fqdn_listname
+ '[EMAIL PROTECTED]'
+ >>> mlist_1.msg_footer
+ u'test footer'
+
+
+Creating a list with owners
+---------------------------
+
+You can also specify a list of owner email addresses. If these addresses are
+not yet known, they will be registered, and new users will be linked to them.
+However the addresses are not verified.
+
+ >>> owners = ['[EMAIL PROTECTED]', '[EMAIL PROTECTED]',
+ ... '[EMAIL PROTECTED]', '[EMAIL PROTECTED]']
+ >>> mlist_2 = create_list('[EMAIL PROTECTED]', owners)
+ >>> flush()
+ >>> mlist_2.fqdn_listname
+ '[EMAIL PROTECTED]'
+ >>> mlist_2.msg_footer
+ u'test footer'
+ >>> sorted(addr.address for addr in mlist_2.owners.addresses)
+ ['[EMAIL PROTECTED]', '[EMAIL PROTECTED]',
+ '[EMAIL PROTECTED]', '[EMAIL PROTECTED]']
+
+None of the owner addresses are verified.
+
+ >>> any(addr.verified_on is not None for addr in mlist_2.owners.addresses)
+ False
+
+However, all addresses are linked to users.
+
+ >>> # The owners have no names yet
+ >>> len(list(mlist_2.owners.users))
+ 4
+
+If you create a mailing list with owner addresses that are already known to
+the system, they won't be created again.
+
+ >>> from Mailman.configuration import config
+ >>> usermgr = config.db.user_manager
+ >>> user_a = usermgr.get_user('[EMAIL PROTECTED]')
+ >>> user_b = usermgr.get_user('[EMAIL PROTECTED]')
+ >>> user_c = usermgr.get_user('[EMAIL PROTECTED]')
+ >>> user_d = usermgr.get_user('[EMAIL PROTECTED]')
+ >>> user_a.real_name = 'Anne Person'
+ >>> user_b.real_name = 'Bart Person'
+ >>> user_c.real_name = 'Caty Person'
+ >>> user_d.real_name = 'Dirk Person'
+ >>> flush()
+
+ >>> mlist_3 = create_list('[EMAIL PROTECTED]', owners)
+ >>> flush()
+ >>> sorted(user.real_name for user in mlist_3.owners.users)
+ ['Anne Person', 'Bart Person', 'Caty Person', 'Dirk Person']
=== modified file 'Mailman/Cgi/create.py'
--- a/Mailman/Cgi/create.py 2007-07-18 15:46:44 +0000
+++ b/Mailman/Cgi/create.py 2007-08-05 12:42:16 +0000
@@ -173,7 +173,7 @@
request_creation(doc, cgidata,
_('List already exists: $safelistname'))
return
- except Errors.BadListNameError, s:
+ except Errors.InvalidEmailAddress, s:
request_creation(doc, cgidata, _('Illegal list name: $s'))
return
except Errors.MMListError:
=== modified file 'Mailman/Errors.py'
--- a/Mailman/Errors.py 2007-08-05 04:32:09 +0000
+++ b/Mailman/Errors.py 2007-08-05 12:42:16 +0000
@@ -39,7 +39,6 @@
class MMCorruptListDatabaseError(MMListError): pass
class MMListNotReadyError(MMListError): pass
class MMListAlreadyExistsError(MMListError): pass
-class BadListNameError(MMListError): pass
# Membership exceptions
class MMMemberError(MailmanException): pass
=== modified file 'Mailman/app/create.py'
--- a/Mailman/app/create.py 2007-08-05 04:32:09 +0000
+++ b/Mailman/app/create.py 2007-08-05 12:42:16 +0000
@@ -23,11 +23,14 @@
from Mailman.app.plugins import get_plugin
from Mailman.app.styles import style_manager
from Mailman.configuration import config
+from Mailman.constants import MemberRole
-def create_list(fqdn_listname):
+def create_list(fqdn_listname, owners=None):
"""Create the named list and apply styles."""
+ if owners is None:
+ owners = []
ValidateEmail(fqdn_listname)
listname, domain = Utils.split_listname(fqdn_listname)
if domain not in config.domains:
@@ -43,4 +46,15 @@
# XXX FIXME
## mta_plugin = get_plugin('mailman.mta')
## mta_plugin().create(mlist)
+ # Create any owners that don't yet exist, and subscribe all addresses as
+ # owners of the mailing list.
+ usermgr = config.db.user_manager
+ for owner_address in owners:
+ addr = usermgr.get_address(owner_address)
+ if addr is None:
+ # XXX Make this use an IRegistrar instead, but that requires
+ # sussing out the IDomain stuff. For now, fake it.
+ user = usermgr.create_user(owner_address)
+ addr = list(user.addresses)[0]
+ addr.subscribe(mlist, MemberRole.owner)
return mlist
=== modified file 'Mailman/app/styles.py'
--- a/Mailman/app/styles.py 2007-08-05 11:30:30 +0000
+++ b/Mailman/app/styles.py 2007-08-05 12:42:16 +0000
@@ -21,6 +21,7 @@
from operator import attrgetter
from zope.interface import implements
+from zope.interface.verify import verifyObject
from Mailman import Utils
from Mailman.Errors import DuplicateStyleError
@@ -261,10 +262,15 @@
yield style
def register(self, style):
+ verifyObject(IStyle, style)
if style.name in self._styles:
raise DuplicateStyleError(style.name)
self._styles[style.name] = style
+ def unregister(self, style):
+ # Let KeyErrors percolate up.
+ del self._styles[style.name]
+
style_manager = StyleManager()
=== modified file 'Mailman/bin/newlist.py'
--- a/Mailman/bin/newlist.py 2007-08-05 04:32:09 +0000
+++ b/Mailman/bin/newlist.py 2007-08-05 12:42:16 +0000
@@ -29,7 +29,6 @@
from Mailman import i18n
from Mailman.app.create import create_list
from Mailman.configuration import config
-from Mailman.constants import MemberRole
from Mailman.initialize import initialize
_ = i18n._
@@ -104,29 +103,14 @@
# Create the mailing list, applying styles as appropriate.
try:
- mlist = create_list(fqdn_listname)
+ mlist = create_list(fqdn_listname, opts.owners)
mlist.preferred_language = opts.language
- except Errors.BadListNameError:
+ except Errors.InvalidEmailAddress:
parser.error(_('Illegal list name: $fqdn_listname'))
except Errors.MMListAlreadyExistsError:
parser.error(_('List already exists: $fqdn_listname'))
except Errors.BadDomainSpecificationError, domain:
parser.error(_('Undefined domain: $domain'))
- except Errors.MMListAlreadyExistsError:
- parser.error(_('List already exists: $fqdn_listname'))
-
- # Create any owners that don't yet exist, and subscribe all addresses as
- # owners of the mailing list.
- usermgr = config.db.user_manager
- for owner_address in opts.owners:
- addr = usermgr.get_address(owner_address)
- if addr is None:
- # XXX Make this use an IRegistrar instead, but that requires
- # sussing out the IDomain stuff. For now, fake it.
- user = usermgr.create_user(owner_address)
- addr = list(user.addresses)[0]
- addr.verified_on = datetime.datetime.now()
- addr.subscribe(mlist, MemberRole.owner)
config.db.flush()
=== modified file 'Mailman/docs/styles.txt'
--- a/Mailman/docs/styles.txt 2007-08-05 11:30:30 +0000
+++ b/Mailman/docs/styles.txt 2007-08-05 12:42:16 +0000
@@ -64,6 +64,7 @@
>>> from zope.interface import implements
>>> from Mailman.interfaces import IStyle
>>> class TestStyle(object):
+ ... implements(IStyle)
... name = 'test'
... priority = 10
... def apply(self, mailing_list):
@@ -130,13 +131,38 @@
u'test footer'
+Unregistering styles
+--------------------
+
+You can unregister a style, making it unavailable in the future.
+
+ >>> style_manager.unregister(style_2)
+ >>> sorted(style.name for style in style_manager.lookup(mlist))
+ ['test']
+
+
Corner cases
------------
If you register a style with the same name as an already registered style, you
get an exception.
- >>> style_manager.register(AnotherTestStyle())
- Traceback (most recent call last):
- ...
- DuplicateStyleError: another
+ >>> style_manager.register(TestStyle())
+ Traceback (most recent call last):
+ ...
+ DuplicateStyleError: test
+
+If you try to register an object that isn't a style, you get an exception.
+
+ >>> style_manager.register(object())
+ Traceback (most recent call last):
+ ...
+ DoesNotImplement: An object does not implement interface
+ <InterfaceClass Mailman.interfaces.styles.IStyle>
+
+If you try to unregister a style that isn't registered, you get an exception.
+
+ >>> style_manager.unregister(style_2)
+ Traceback (most recent call last):
+ ...
+ KeyError: 'another'
=== modified file 'Mailman/interfaces/styles.py'
--- a/Mailman/interfaces/styles.py 2007-08-05 04:32:09 +0000
+++ b/Mailman/interfaces/styles.py 2007-08-05 12:42:16 +0000
@@ -84,3 +84,10 @@
:raises DuplicateStyleError: if a style with the same name was already
registered.
"""
+
+ def unregister(style):
+ """Unregister the style.
+
+ :param style: an IStyle.
+ :raises KeyError: If the style's name is not currently registered.
+ """
=== modified file 'Mailman/tests/test_documentation.py'
--- a/Mailman/tests/test_documentation.py 2007-08-02 14:47:56 +0000
+++ b/Mailman/tests/test_documentation.py 2007-08-05 12:42:16 +0000
@@ -22,6 +22,8 @@
import unittest
import Mailman
+
+from Mailman.app.styles import style_manager
from Mailman.configuration import config
from Mailman.database import flush
@@ -56,6 +58,10 @@
for dirpath, dirnames, filenames in os.walk(config.QUEUE_DIR):
for filename in filenames:
os.remove(os.path.join(dirpath, filename))
+ # Remove all but the default style.
+ for style in style_manager.styles:
+ if style.name <> 'default':
+ style_manager.unregister(style)
--
(no title)
https://code.launchpad.net/~mailman-coders/mailman/3.0
You are receiving this branch notification because you are subscribed to it.
To unsubscribe from this branch go to
https://code.launchpad.net/~mailman-coders/mailman/3.0/+subscription/mailman-checkins.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe:
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org