From da566eb047608ed2e65c71dd25979f01c825c843 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 21 Aug 2009 16:11:50 -0400 Subject: * Updated NEWS.txt for 3.0a3. * Use the IListManager() adapter instead of hanging the list manager off of config.db. This makes the code somewhat cleaner. --- src/attic/add_members.py | 186 ++++++++++++++++++++++++++++++++++++ src/mailman/Archiver/HyperArch.py | 3 +- src/mailman/app/lifecycle.py | 5 +- src/mailman/app/registrar.py | 3 +- src/mailman/bin/add_members.py | 186 ------------------------------------ src/mailman/bin/inject.py | 3 +- src/mailman/commands/cli_lists.py | 6 +- src/mailman/commands/cli_members.py | 3 +- src/mailman/config/configure.zcml | 6 ++ src/mailman/database/__init__.py | 2 - src/mailman/database/listmanager.py | 20 ++-- 11 files changed, 220 insertions(+), 203 deletions(-) create mode 100644 src/attic/add_members.py delete mode 100644 src/mailman/bin/add_members.py (limited to 'src') diff --git a/src/attic/add_members.py b/src/attic/add_members.py new file mode 100644 index 000000000..540c0facb --- /dev/null +++ b/src/attic/add_members.py @@ -0,0 +1,186 @@ +# Copyright (C) 1998-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 . + +import os +import sys +import codecs + +from cStringIO import StringIO +from email.utils import parseaddr + +from mailman import Utils +from mailman import i18n +from mailman.app.membership import add_member +from mailman.config import config +from mailman.core import errors +from mailman.email.message import UserNotification +from mailman.interfaces.member import AlreadySubscribedError, DeliveryMode +from mailman.options import SingleMailingListOptions + +_ = i18n._ + + + +class ScriptOptions(SingleMailingListOptions): + usage=_("""\ +%prog [options] + +Add members to a list. 'listname' is the name of the Mailman list you are +adding members to; the list must already exist. + +You must supply at least one of -r and -d options. At most one of the +files can be '-'. +""") + + def add_options(self): + super(ScriptOptions, self).add_options() + self.parser.add_option( + '-r', '--regular-members-file', + type='string', dest='regular', help=_("""\ +A file containing addresses of the members to be added, one address per line. +This list of people become non-digest members. If file is '-', read addresses +from stdin.""")) + self.parser.add_option( + '-d', '--digest-members-file', + type='string', dest='digest', help=_("""\ +Similar to -r, but these people become digest members.""")) + self.parser.add_option( + '-w', '--welcome-msg', + type='yesno', metavar='', help=_("""\ +Set whether or not to send the list members a welcome message, overriding +whatever the list's 'send_welcome_msg' setting is.""")) + self.parser.add_option( + '-a', '--admin-notify', + type='yesno', metavar='', help=_("""\ +Set whether or not to send the list administrators a notification on the +success/failure of these subscriptions, overriding whatever the list's +'admin_notify_mchanges' setting is.""")) + + def sanity_check(self): + if not self.options.listname: + self.parser.error(_('Missing listname')) + if len(self.arguments) > 0: + self.parser.print_error(_('Unexpected arguments')) + if self.options.regular is None and self.options.digest is None: + parser.error(_('At least one of -r or -d is required')) + if self.options.regular == '-' and self.options.digest == '-': + parser.error(_("-r and -d cannot both be '-'")) + + + +def readfile(filename): + if filename == '-': + fp = sys.stdin + else: + # XXX Need to specify other encodings. + fp = codecs.open(filename, encoding='utf-8') + # Strip all the lines of whitespace and discard blank lines + try: + return set(line.strip() for line in fp if line) + finally: + if fp is not sys.stdin: + fp.close() + + + +class Tee: + def __init__(self, outfp): + self._outfp = outfp + + def write(self, msg): + sys.stdout.write(msg) + self._outfp.write(msg) + + + +def addall(mlist, subscribers, delivery_mode, ack, admin_notify, outfp): + tee = Tee(outfp) + for subscriber in subscribers: + try: + fullname, address = parseaddr(subscriber) + # Watch out for the empty 8-bit string. + if not fullname: + fullname = u'' + password = Utils.MakeRandomPassword() + add_member(mlist, address, fullname, password, delivery_mode, + unicode(config.mailman.default_language)) + # XXX Support ack and admin_notify + except AlreadySubscribedError: + print >> tee, _('Already a member: $subscriber') + except errors.InvalidEmailAddress: + if not address: + print >> tee, _('Bad/Invalid email address: blank line') + else: + print >> tee, _('Bad/Invalid email address: $subscriber') + else: + print >> tee, _('Subscribing: $subscriber') + + + +def main(): + options = ScriptOptions() + options.initialize() + + fqdn_listname = options.options.listname + mlist = config.db.list_manager.get(fqdn_listname) + if mlist is None: + parser.error(_('No such list: $fqdn_listname')) + + # Set up defaults. + send_welcome_msg = (options.options.welcome_msg + if options.options.welcome_msg is not None + else mlist.send_welcome_msg) + admin_notify = (options.options.admin_notify + if options.options.admin_notify is not None + else mlist.admin_notify) + + with i18n.using_language(mlist.preferred_language): + if options.options.digest: + dmembers = readfile(options.options.digest) + else: + dmembers = set() + if options.options.regular: + nmembers = readfile(options.options.regular) + else: + nmembers = set() + + if not dmembers and not nmembers: + print _('Nothing to do.') + sys.exit(0) + + outfp = StringIO() + if nmembers: + addall(mlist, nmembers, DeliveryMode.regular, + send_welcome_msg, admin_notify, outfp) + + if dmembers: + addall(mlist, dmembers, DeliveryMode.mime_digests, + send_welcome_msg, admin_notify, outfp) + + config.db.commit() + + if admin_notify: + subject = _('$mlist.real_name subscription notification') + msg = UserNotification( + mlist.owner, mlist.no_reply_address, subject, + outfp.getvalue(), mlist.preferred_language) + msg.send(mlist) + + + +if __name__ == '__main__': + main() diff --git a/src/mailman/Archiver/HyperArch.py b/src/mailman/Archiver/HyperArch.py index d78831e8e..b3601f5fa 100644 --- a/src/mailman/Archiver/HyperArch.py +++ b/src/mailman/Archiver/HyperArch.py @@ -49,6 +49,7 @@ from mailman import i18n from mailman.Archiver import HyperDatabase from mailman.Archiver import pipermail from mailman.config import config +from mailman.interfaces.listmanager import IListManager log = logging.getLogger('mailman.error') @@ -319,7 +320,7 @@ class Article(pipermail.Article): listname = d.get('__listname') if listname: del d['__listname'] - d['_mlist'] = config.db.list_manager.get(listname) + d['_mlist'] = IListManager(config).get(listname) if not d.has_key('_lang'): if hasattr(self, '_mlist'): self._lang = self._mlist.preferred_language diff --git a/src/mailman/app/lifecycle.py b/src/mailman/app/lifecycle.py index d7a8ec1a7..b7f30afd8 100644 --- a/src/mailman/app/lifecycle.py +++ b/src/mailman/app/lifecycle.py @@ -34,6 +34,7 @@ from mailman.config import config from mailman.email.validate import validate from mailman.interfaces.domain import ( BadDomainSpecificationError, IDomainManager) +from mailman.interfaces.listmanager import IListManager from mailman.interfaces.member import MemberRole from mailman.utilities.modules import call_name @@ -51,7 +52,7 @@ def create_list(fqdn_listname, owners=None): listname, domain = fqdn_listname.split('@', 1) if domain not in IDomainManager(config): raise BadDomainSpecificationError(domain) - mlist = config.db.list_manager.create(fqdn_listname) + mlist = IListManager(config).create(fqdn_listname) for style in config.style_manager.lookup(mlist): style.apply(mlist) # Coordinate with the MTA, as defined in the configuration file. @@ -80,7 +81,7 @@ def remove_list(fqdn_listname, mailing_list=None, archives=True): for member in mailing_list.subscribers.members: member.unsubscribe() # Delete the mailing list from the database. - config.db.list_manager.delete(mailing_list) + IListManager(config).delete(mailing_list) # Do the MTA-specific list deletion tasks call_name(config.mta.incoming).create(mailing_list) # Remove the list directory. diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py index 4ec7991d6..3161ed149 100644 --- a/src/mailman/app/registrar.py +++ b/src/mailman/app/registrar.py @@ -35,6 +35,7 @@ from mailman.email.message import UserNotification from mailman.email.validate import validate from mailman.i18n import _ from mailman.interfaces.domain import IDomain +from mailman.interfaces.listmanager import IListManager from mailman.interfaces.member import MemberRole from mailman.interfaces.pending import IPendable from mailman.interfaces.registrar import IRegistrar @@ -136,7 +137,7 @@ class Registrar: # to the list right now. list_name = pendable.get('list_name') if list_name is not None: - mlist = config.db.list_manager.get(list_name) + mlist = IListManager(config).get(list_name) if mlist: addr.subscribe(mlist, MemberRole.member) return True diff --git a/src/mailman/bin/add_members.py b/src/mailman/bin/add_members.py deleted file mode 100644 index 540c0facb..000000000 --- a/src/mailman/bin/add_members.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (C) 1998-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 . - -import os -import sys -import codecs - -from cStringIO import StringIO -from email.utils import parseaddr - -from mailman import Utils -from mailman import i18n -from mailman.app.membership import add_member -from mailman.config import config -from mailman.core import errors -from mailman.email.message import UserNotification -from mailman.interfaces.member import AlreadySubscribedError, DeliveryMode -from mailman.options import SingleMailingListOptions - -_ = i18n._ - - - -class ScriptOptions(SingleMailingListOptions): - usage=_("""\ -%prog [options] - -Add members to a list. 'listname' is the name of the Mailman list you are -adding members to; the list must already exist. - -You must supply at least one of -r and -d options. At most one of the -files can be '-'. -""") - - def add_options(self): - super(ScriptOptions, self).add_options() - self.parser.add_option( - '-r', '--regular-members-file', - type='string', dest='regular', help=_("""\ -A file containing addresses of the members to be added, one address per line. -This list of people become non-digest members. If file is '-', read addresses -from stdin.""")) - self.parser.add_option( - '-d', '--digest-members-file', - type='string', dest='digest', help=_("""\ -Similar to -r, but these people become digest members.""")) - self.parser.add_option( - '-w', '--welcome-msg', - type='yesno', metavar='', help=_("""\ -Set whether or not to send the list members a welcome message, overriding -whatever the list's 'send_welcome_msg' setting is.""")) - self.parser.add_option( - '-a', '--admin-notify', - type='yesno', metavar='', help=_("""\ -Set whether or not to send the list administrators a notification on the -success/failure of these subscriptions, overriding whatever the list's -'admin_notify_mchanges' setting is.""")) - - def sanity_check(self): - if not self.options.listname: - self.parser.error(_('Missing listname')) - if len(self.arguments) > 0: - self.parser.print_error(_('Unexpected arguments')) - if self.options.regular is None and self.options.digest is None: - parser.error(_('At least one of -r or -d is required')) - if self.options.regular == '-' and self.options.digest == '-': - parser.error(_("-r and -d cannot both be '-'")) - - - -def readfile(filename): - if filename == '-': - fp = sys.stdin - else: - # XXX Need to specify other encodings. - fp = codecs.open(filename, encoding='utf-8') - # Strip all the lines of whitespace and discard blank lines - try: - return set(line.strip() for line in fp if line) - finally: - if fp is not sys.stdin: - fp.close() - - - -class Tee: - def __init__(self, outfp): - self._outfp = outfp - - def write(self, msg): - sys.stdout.write(msg) - self._outfp.write(msg) - - - -def addall(mlist, subscribers, delivery_mode, ack, admin_notify, outfp): - tee = Tee(outfp) - for subscriber in subscribers: - try: - fullname, address = parseaddr(subscriber) - # Watch out for the empty 8-bit string. - if not fullname: - fullname = u'' - password = Utils.MakeRandomPassword() - add_member(mlist, address, fullname, password, delivery_mode, - unicode(config.mailman.default_language)) - # XXX Support ack and admin_notify - except AlreadySubscribedError: - print >> tee, _('Already a member: $subscriber') - except errors.InvalidEmailAddress: - if not address: - print >> tee, _('Bad/Invalid email address: blank line') - else: - print >> tee, _('Bad/Invalid email address: $subscriber') - else: - print >> tee, _('Subscribing: $subscriber') - - - -def main(): - options = ScriptOptions() - options.initialize() - - fqdn_listname = options.options.listname - mlist = config.db.list_manager.get(fqdn_listname) - if mlist is None: - parser.error(_('No such list: $fqdn_listname')) - - # Set up defaults. - send_welcome_msg = (options.options.welcome_msg - if options.options.welcome_msg is not None - else mlist.send_welcome_msg) - admin_notify = (options.options.admin_notify - if options.options.admin_notify is not None - else mlist.admin_notify) - - with i18n.using_language(mlist.preferred_language): - if options.options.digest: - dmembers = readfile(options.options.digest) - else: - dmembers = set() - if options.options.regular: - nmembers = readfile(options.options.regular) - else: - nmembers = set() - - if not dmembers and not nmembers: - print _('Nothing to do.') - sys.exit(0) - - outfp = StringIO() - if nmembers: - addall(mlist, nmembers, DeliveryMode.regular, - send_welcome_msg, admin_notify, outfp) - - if dmembers: - addall(mlist, dmembers, DeliveryMode.mime_digests, - send_welcome_msg, admin_notify, outfp) - - config.db.commit() - - if admin_notify: - subject = _('$mlist.real_name subscription notification') - msg = UserNotification( - mlist.owner, mlist.no_reply_address, subject, - outfp.getvalue(), mlist.preferred_language) - msg.send(mlist) - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/inject.py b/src/mailman/bin/inject.py index 73f1b9015..591d6697b 100644 --- a/src/mailman/bin/inject.py +++ b/src/mailman/bin/inject.py @@ -24,6 +24,7 @@ from mailman import Utils from mailman.configuration import config from mailman.i18n import _ from mailman.inject import inject_text +from mailman.interfaces.listmanager import IListManager from mailman.message import Message from mailman.options import SingleMailingListOptions @@ -71,7 +72,7 @@ def main(): options.parser.error(_('Bad queue directory: $qdir')) fqdn_listname = options.options.listname - mlist = config.db.list_manager.get(fqdn_listname) + mlist = IListManager(config).get(fqdn_listname) if mlist is None: options.parser.error(_('No such list: $fqdn_listname')) diff --git a/src/mailman/commands/cli_lists.py b/src/mailman/commands/cli_lists.py index b95d1a779..95c7b650c 100644 --- a/src/mailman/commands/cli_lists.py +++ b/src/mailman/commands/cli_lists.py @@ -39,7 +39,7 @@ from mailman.i18n import _, using_language from mailman.interfaces.command import ICLISubCommand from mailman.interfaces.domain import ( BadDomainSpecificationError, IDomainManager) -from mailman.interfaces.listmanager import ListAlreadyExistsError +from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError @@ -76,7 +76,7 @@ class Lists: def process(self, args): """See `ICLISubCommand`.""" mailing_lists = [] - list_manager = config.db.list_manager + list_manager = IListManager(config) # Gather the matching mailing lists. for fqdn_name in sorted(list_manager.names): mlist = list_manager.get(fqdn_name) @@ -251,7 +251,7 @@ remove any residual archives.""")) assert len(args.listname) == 1, ( 'Unexpected positional arguments: %s' % args.listname) fqdn_listname = args.listname[0] - mlist = config.db.list_manager.get(fqdn_listname) + mlist = IListManager(config).get(fqdn_listname) if mlist is None: if args.archives: log(_('No such list: $fqdn_listname; ' diff --git a/src/mailman/commands/cli_members.py b/src/mailman/commands/cli_members.py index 7e22166ed..5a2a419f7 100644 --- a/src/mailman/commands/cli_members.py +++ b/src/mailman/commands/cli_members.py @@ -35,6 +35,7 @@ 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.listmanager import IListManager from mailman.interfaces.member import DeliveryMode @@ -67,7 +68,7 @@ class Members: assert len(args.listname) == 1, ( 'Unexpected positional arguments: %s' % args.listname) fqdn_listname = args.listname[0] - mlist = config.db.list_manager.get(fqdn_listname) + mlist = IListManager(config).get(fqdn_listname) if mlist is None: self.parser.error(_('No such list: $fqdn_listname')) if args.filename == '-': diff --git a/src/mailman/config/configure.zcml b/src/mailman/config/configure.zcml index cc1a9face..7e139980c 100644 --- a/src/mailman/config/configure.zcml +++ b/src/mailman/config/configure.zcml @@ -6,6 +6,12 @@ + +