1
# Copyright (C) 2007-2012 by the Free Software Foundation, Inc.
3
# This file is part of GNU Mailman.
5
# GNU Mailman is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free
7
# Software Foundation, either version 3 of the License, or (at your option)
10
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
# You should have received a copy of the GNU General Public License along with
16
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
21
from zope.component import getUtility
23
from mailman import Utils
24
from mailman import passwords
25
from mailman.app.membership import add_member
26
from mailman.app.notifications import (
27
send_admin_subscription_notice, send_welcome_message)
28
from mailman.configuration import config
29
from mailman.core.i18n import _
30
from mailman.initialize import initialize
31
from mailman.interfaces.members import DeliveryMode
32
from mailman.interfaces.usermanager import IUserManager
33
from mailman.version import MAILMAN_VERSION
37
'regular': DeliveryMode.regular,
38
'plain': DeliveryMode.plaintext_digests,
39
'mime': DeliveryMode.mime_digests,
45
parser = optparse.OptionParser(version=MAILMAN_VERSION,
47
%prog [options] csv-file
49
Set the membership of a mailing list to that described in a CSV file. Each
50
row of the CSV file has the following format. Only the address column is
54
- full name (default: the empty string)
55
- delivery mode (default: regular delivery) [1]
57
[1] The delivery mode is a case insensitive string of the following values:
59
regular - regular, i.e. immediate delivery
60
mime - MIME digest delivery
61
plain - plain text (RFC 1153) digest delivery
63
Any address not included in the CSV file is removed from the list membership.
65
parser.add_option('-l', '--listname',
66
type='string', help=_("""\
67
Mailng list to set the membership for."""))
68
parser.add_option('-w', '--welcome-msg',
69
type='string', metavar='<y|n>', help=_("""\
70
Set whether or not to send the list members a welcome message, overriding
71
whatever the list's 'send_welcome_msg' setting is."""))
72
parser.add_option('-a', '--admin-notify',
73
type='string', metavar='<y|n>', help=_("""\
74
Set whether or not to send the list administrators a notification on the
75
success/failure of these subscriptions, overriding whatever the list's
76
'admin_notify_mchanges' setting is."""))
77
parser.add_option('-v', '--verbose', action='store_true',
78
help=_('Increase verbosity'))
79
parser.add_option('-C', '--config',
80
help=_('Alternative configuration file to use'))
81
opts, args = parser.parse_args()
82
if opts.welcome_msg is not None:
83
ch = opts.welcome_msg[0].lower()
85
opts.welcome_msg = True
87
opts.welcome_msg = False
89
parser.error(_('Illegal value for -w: $opts.welcome_msg'))
90
if opts.admin_notify is not None:
91
ch = opts.admin_notify[0].lower()
93
opts.admin_notify = True
95
opts.admin_notify = False
97
parser.error(_('Illegal value for -a: $opts.admin_notify'))
98
return parser, opts, args
102
def parse_file(filename):
104
with open(filename) as fp:
105
for row in csv.reader(fp):
111
delivery_mode = DeliveryMode.regular
113
address, real_name = row
114
delivery_mode = DeliveryMode.regular
116
# Ignore extra columns
117
address, real_name = row[0:2]
118
delivery_mode = DELIVERY_MODES.get(row[2].lower())
119
if delivery_mode is None:
120
delivery_mode = DeliveryMode.regular
121
members[address] = real_name, delivery_mode
127
parser, opts, args = parseargs()
128
initialize(opts.config)
130
mlist = config.db.list_manager.get(opts.listname)
132
parser.error(_('No such list: $opts.listname'))
135
if opts.welcome_msg is None:
136
send_welcome_msg = mlist.send_welcome_msg
138
send_welcome_msg = opts.welcome_msg
139
if opts.admin_notify is None:
140
admin_notify = mlist.admin_notify_mchanges
142
admin_notify = opts.admin_notify
144
# Parse the csv files.
146
for filename in args:
147
member_data.update(parse_file(filename))
149
future_members = set(member_data)
150
current_members = set(obj.address for obj in mlist.members.addresses)
151
add_members = future_members - current_members
152
delete_members = current_members - future_members
153
change_members = current_members & future_members
155
with _.using(mlist.preferred_language):
156
# Start by removing all the delete members.
157
for address in delete_members:
158
print _('deleting address: $address')
159
member = mlist.members.get_member(address)
161
# For all members that are in both lists, update their full name and
163
for address in change_members:
164
print _('updating address: $address')
165
real_name, delivery_mode = member_data[address]
166
member = mlist.members.get_member(address)
167
member.preferences.delivery_mode = delivery_mode
168
user = getUtility(IUserManager).get_user(address)
169
user.real_name = real_name
170
for address in add_members:
171
print _('adding address: $address')
172
real_name, delivery_mode = member_data[address]
173
password = passwords.make_secret(
174
Utils.MakeRandomPassword(),
175
passwords.lookup_scheme(config.PASSWORD_SCHEME))
176
add_member(mlist, address, real_name, password, delivery_mode,
177
mlist.preferred_language, send_welcome_msg,
180
send_welcome_message(mlist, address, language, delivery_mode)
182
send_admin_subscription_notice(mlist, address, real_name)
188
if __name__ == '__main__':