diff options
| -rw-r--r-- | src/mailman/app/membership.py | 2 | ||||
| -rw-r--r-- | src/mailman/commands/cli_members.py | 44 | ||||
| -rw-r--r-- | src/mailman/commands/docs/members.txt | 60 |
3 files changed, 105 insertions, 1 deletions
diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py index 4022d5727..411083694 100644 --- a/src/mailman/app/membership.py +++ b/src/mailman/app/membership.py @@ -89,7 +89,7 @@ def add_member(mlist, address, realname, password, delivery_mode, language): user = config.db.user_manager.create_user() user.real_name = (realname if realname else address_obj.real_name) user.link(address_obj) - # Since created the user, then the member, and set preferences on the + # Since created the user, then the member, and set preferences on the # appropriate object. user.password = password user.preferences.preferred_language = language diff --git a/src/mailman/commands/cli_members.py b/src/mailman/commands/cli_members.py index 9d9a892d5..7e22166ed 100644 --- a/src/mailman/commands/cli_members.py +++ b/src/mailman/commands/cli_members.py @@ -25,10 +25,17 @@ __all__ = [ ] +import sys +import codecs + +from email.utils import parseaddr from zope.interface import implements +from mailman.app.membership import add_member +from mailman.config import config from mailman.i18n import _ from mailman.interfaces.command import ICLISubCommand +from mailman.interfaces.member import DeliveryMode @@ -41,6 +48,43 @@ class Members: def add(self, parser, command_parser): """See `ICLISubCommand`.""" + command_parser.add_argument( + '-a', '--add', + dest='filename', + help=_('Add all member addresses in FILENAME. FILENAME can be ' + "'-' to indicate standard input.")) + # Required positional argument. + command_parser.add_argument( + 'listname', metavar='LISTNAME', nargs=1, + help=_("""\ + The 'fully qualified list name', i.e. the posting address of the + mailing list. It must be a valid email address and the domain + must be registered with Mailman. List names are forced to lower + case.""")) def process(self, args): """See `ICLISubCommand`.""" + assert len(args.listname) == 1, ( + 'Unexpected positional arguments: %s' % args.listname) + fqdn_listname = args.listname[0] + mlist = config.db.list_manager.get(fqdn_listname) + if mlist is None: + self.parser.error(_('No such list: $fqdn_listname')) + if args.filename == '-': + fp = sys.stdin + else: + fp = codecs.open(args.filename, 'r', 'utf-8') + try: + for line in fp: + real_name, email = parseaddr(line) + # If not given in the input data, parseaddr() will return the + # empty string, as opposed to the empty unicode. We need a + # unicode real name here. + if real_name == '': + real_name = u'' + add_member(mlist, email, real_name, None, + DeliveryMode.regular, mlist.preferred_language.code) + finally: + if fp is not sys.stdin: + fp.close() + config.db.commit() diff --git a/src/mailman/commands/docs/members.txt b/src/mailman/commands/docs/members.txt new file mode 100644 index 000000000..c1374277a --- /dev/null +++ b/src/mailman/commands/docs/members.txt @@ -0,0 +1,60 @@ +============== +Adding members +============== + +You can add members to a mailing list from the command line. + + >>> from mailman.app.lifecycle import create_list + >>> mlist = create_list('test@example.com') + + >>> class FakeArgs: + ... filename = None + ... listname = None + >>> args = FakeArgs() + + >>> from mailman.commands.cli_members import Members + >>> command = Members() + +To do so, you need a file containing email addresses and full names that can +be parsed by email.utils.parseaddr(). + + >>> addresses = [ + ... ] + + >>> import os + >>> path = os.path.join(config.VAR_DIR, 'addresses.txt') + >>> with open(path, 'w') as fp: + ... for address in ('aperson@example.com', + ... 'Bart Person <bperson@example.com>', + ... 'cperson@example.com (Cate Person)', + ... ): + ... print >> fp, address + + >>> args.filename = path + >>> args.listname = [mlist.fqdn_listname] + >>> command.process(args) + + >>> sorted(address.address for address in mlist.members.addresses) + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com'] + +You can also specify '-' as the filename, in which case the addresses are +taken from standard input. + + >>> from StringIO import StringIO + >>> fp = StringIO() + >>> for address in ('dperson@example.com', + ... 'Elly Person <eperson@example.com>', + ... 'fperson@example.com (Fred Person)', + ... ): + ... print >> fp, address + >>> fp.seek(0) + >>> import sys + >>> sys.stdin = fp + + >>> args.filename = '-' + >>> command.process(args) + >>> sys.stdin = sys.__stdin__ + + >>> sorted(address.address for address in mlist.members.addresses) + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com', + u'dperson@example.com', u'eperson@example.com', u'fperson@example.com'] |
