diff options
| author | bwarsaw | 2001-04-09 04:30:50 +0000 |
|---|---|---|
| committer | bwarsaw | 2001-04-09 04:30:50 +0000 |
| commit | f8ca458474632d55b096c2eebed3f54861032447 (patch) | |
| tree | 2333f6ab10661172add29a8104881f339df27375 /Mailman/Cgi/admin.py | |
| parent | 9ad99881142e1a69d7881dedfa1959c44fb31ccd (diff) | |
| download | mailman-f8ca458474632d55b096c2eebed3f54861032447.tar.gz mailman-f8ca458474632d55b096c2eebed3f54861032447.tar.zst mailman-f8ca458474632d55b096c2eebed3f54861032447.zip | |
Diffstat (limited to 'Mailman/Cgi/admin.py')
| -rw-r--r-- | Mailman/Cgi/admin.py | 519 |
1 files changed, 349 insertions, 170 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index f69903fb0..300e6d653 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -19,10 +19,12 @@ """ import os +import re import cgi import types import sha import urllib +from string import lowercase, digits from mimelib.address import unquote @@ -357,11 +359,23 @@ def show_results(mlist, doc, category, category_suffix, cgidata): # Translate v = _(v) if k == category: - # BAW: Is there a better UI for the category we're currently - # displaying? I'd like a non-underlined, non-colored, italicized, - # but live link. - v = '<em><font size="+2">%s</font></em>' % v - categorylinks.AddItem(Link("%s/%s" % (adminurl, k), v)) + # Membership management has some subcategories + if k == category == 'members': + subcat_items = [] + subcat = Utils.GetPathPieces()[-1] + if subcat == 'members': + subcat = 'list' + for sub, text in (('list', _('Membership List')), + ('add', _('Mass Subscription')), + ('remove', _('Mass Removal'))): + if sub == subcat: + text = Bold('[%s]' % text).Format() + subcat_items.append(Link('%s/%s/%s' % (adminurl, k, sub), + text)) + v += UnorderedList(*subcat_items).Format() + else: + v = Bold('[%s]' % v).Format() + categorylinks.AddItem(Link('%s/%s' % (adminurl, k), v)) # Add all the links to the links table... linktable.AddRow([categorylinks, otherlinks]) linktable.AddRowInfo(max(linktable.GetCurrentRowIndex(), 0), @@ -371,10 +385,10 @@ def show_results(mlist, doc, category, category_suffix, cgidata): doc.AddItem('<hr>') # Now we need to craft the form that will be submitted, which will contain # all the variable settings, etc. This is a bit of a kludge because we - # know that the `autoreply' category supports file uploads. + # know that the autoreply and members categories supports file uploads. if category_suffix: encoding = None - if category_suffix == 'autoreply': + if category_suffix in ('autoreply', 'members'): # These have file uploads encoding = 'multipart/form-data' form = Form('%s/%s' % (adminurl, category_suffix), encoding=encoding) @@ -393,7 +407,7 @@ def show_results(mlist, doc, category, category_suffix, cgidata): andpassmsg + '<p>') - form.AddItem(show_variables(mlist, category, cgidata)) + form.AddItem(show_variables(mlist, category, cgidata, doc, form)) if category == 'general': form.AddItem(Center(password_inputs())) @@ -405,11 +419,11 @@ def show_results(mlist, doc, category, category_suffix, cgidata): -def show_variables(mlist, category, cgidata): +def show_variables(mlist, category, cgidata, doc, form): # Produce the category specific variable options table if category == 'members': # Special case for members section. - return membership_options(mlist, cgidata) + return membership_options(mlist, cgidata, doc, form) options = get_config_options(mlist, category) @@ -584,103 +598,178 @@ def get_item_gui_description(mlist, category, varname, descr, detailsp): -def membership_options(mlist, cgidata): +def membership_options(mlist, cgidata, doc, form): + # Figure out which subcategory we should display + subcat = Utils.GetPathPieces()[-1] + if subcat not in ('list', 'add', 'remove'): + subcat = 'list' + # Show the main stuff container = Container() header = Table(width="100%") - header.AddRow([Center(Header(2, _("Membership Management")))]) + # If we're in the list subcategory, show the membership list + if subcat == 'add': + header.AddRow([Center(Header(2, _('Mass Subscriptions')))]) + header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0, + colspan=2, bgcolor='#99ccff') + container.AddItem(header) + mass_subscribe(mlist, container) + return container + if subcat == 'remove': + header.AddRow([Center(Header(2, _('Mass Removals')))]) + header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0, + colspan=2, bgcolor='#99ccff') + container.AddItem(header) + mass_remove(mlist, container) + return container + # Otherwise... + header.AddRow([Center(Header(2, _('Membership List')))]) header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0, - colspan=2, bgcolor="#99ccff") + colspan=2, bgcolor='#99ccff') container.AddItem(header) - user_table = Table(width="90%", border='2') - user_table.AddRow([Center(Header(4, _("Membership List")))]) - user_table.AddCellInfo(user_table.GetCurrentRowIndex(), - user_table.GetCurrentCellIndex(), - bgcolor="#cccccc", colspan=9) - membercnt = len(mlist.members) + len(mlist.digest_members) + usertable = Table(width="90%", border='2') + # If there are more members than allowed by chunksize, then we split the + # membership up alphabetically. Otherwise just display them all. chunksz = mlist.admin_member_chunksize - user_table.AddRow( - [Center(Italic(_( - "(%(membercnt)s members total, max. %(chunksz)s at a time displayed)") - ))]) - user_table.AddCellInfo(user_table.GetCurrentRowIndex(), - user_table.GetCurrentCellIndex(), - bgcolor="#cccccc", colspan=9) - - user_table.AddRow(map(Center, [_('member address'), _('subscr'), - _('hide'), _('nomail'), _('ack'), - _('not metoo'), - _('digest'), _('plain'), _('language')])) - rowindex = user_table.GetCurrentRowIndex() - for i in range(9): - user_table.AddCellInfo(rowindex, i, bgcolor='#cccccc') all = mlist.GetMembers() + mlist.GetDigestMembers() - if len(all) > mlist.admin_member_chunksize: - chunks = Utils.chunkify(all, mlist.admin_member_chunksize) - if not cgidata.has_key("chunk"): - chunk = 0 + all.sort(lambda x, y: cmp(x.lower(), y.lower())) + # See if the query has a regular expression + regexp = '' + if cgidata.has_key('findmember'): + regexp = cgidata['findmember'].value + try: + cre = re.compile(regexp, re.IGNORECASE) + except re.error: + add_error_message(doc, 'Bad regular expression: ' + regexp) else: - chunk = int(cgidata["chunk"].value) - all = chunks[chunk] - - footer = _('''<p><em>To View other sections, click on the appropriate - range listed below</em>''') - - chunk_indices = range(len(chunks)) - chunk_indices.remove(chunk) - buttons = [] - for ci in chunk_indices: - start, end = chunks[ci][0], chunks[ci][-1] - url = mlist.GetScriptURL('admin') - buttons.append("<a href=%(url)s/members?chunk=%(ci)d>" + - _("from %(start)s to %(end)s") + "</a>") - buttons = apply(UnorderedList, tuple(buttons)) - footer = footer + buttons.Format() + "<p>" + all = [s for s in all if cre.search(s)] + chunkindex = None + bucket = None + actionurl = None + if len(all) < chunksz: + members = all + else: + # Split them up alphabetically, and then split the alphabetical + # listing by chunks + buckets = {} + for addr in all: + members = buckets.setdefault(addr[0].lower(), []) + members.append(addr) + # Now figure out which bucket we want + bucket = 'a' + # POST methods, even if their actions have a query string, don't get + # put into FieldStorage's keys :-( + qs = cgi.parse_qs(os.environ['QUERY_STRING']) + if qs.has_key('letter'): + bucket = qs['letter'][0].lower() + if bucket not in digits + lowercase: + bucket = None + if not bucket or not buckets.has_key(bucket): + keys = buckets.keys() + keys.sort() + bucket = keys[0] + members = buckets[bucket] + action = mlist.GetScriptURL('admin') + '/members?letter=%s' % bucket + if len(members) <= chunksz: + form.set_action(action) + else: + i, r = divmod(len(members), chunksz) + numchunks = i + (not not r * 1) + # Now chunk them up + chunkindex = 0 + if qs.has_key('chunk'): + try: + chunkindex = int(qs['chunk'][0]) + except ValueError: + chunkindex = 0 + if chunkindex < 0 or chunkindex > numchunks: + chunkindex = 0 + members = members[chunkindex*chunksz:(chunkindex+1)*chunksz] + # And set the action URL + form.set_action(action + '&chunk=%s' % chunkindex) + # So now members holds all the addresses we're going to display + allcnt = len(all) + if bucket: + membercnt = len(members) + usertable.AddRow([Center(Italic(_( + '%(allcnt)s members total, %(membercnt)s shown')))]) + else: + usertable.AddRow([Center(Italic(_('%(allcnt)s members total')))]) + usertable.AddCellInfo(usertable.GetCurrentRowIndex(), + usertable.GetCurrentCellIndex(), + bgcolor="#cccccc", colspan=9) + # Add the alphabetical links + if bucket: + cells = [] + for letter in digits + lowercase: + if not buckets.get(letter): + continue + url = mlist.GetScriptURL('admin') + '/members?letter=%s' % letter + if letter == bucket: + show = Bold('[%s]' % letter.upper()).Format() + else: + show = letter.upper() + cells.append(Link(url, show).Format()) + joiner = ' '*2 + '\n' + usertable.AddRow([Center(joiner.join(cells))]) + usertable.AddCellInfo(usertable.GetCurrentRowIndex(), + usertable.GetCurrentCellIndex(), + bgcolor="#cccccc", colspan=9) + usertable.AddRow([Center(h) for h in (_('member address<br>member name'), + _('subscr'), _('hide'), _('nomail'), + _('ack'), _('not metoo'), + _('digest'), _('plain'), + _('language'))]) + rowindex = usertable.GetCurrentRowIndex() + for i in range(9): + usertable.AddCellInfo(rowindex, i, bgcolor='#cccccc') + # Find the longest name in the list + if members: + longest = max([len(s) for s in members]) else: - all.sort() - footer = "<p>" - for member in all: - mtext = '<a href="%s">%s</a>' % ( - mlist.GetOptionsURL(member, obscure=1), - mlist.GetUserSubscribedAddress(member)) - cells = [mtext + - '<input type="hidden" name="user" value="%s">' % - urllib.quote(member), - Center(CheckBox(member + "_subscribed", "on", 1).Format())] - for opt in ("hide", "nomail", "ack", "notmetoo"): - if mlist.GetUserOption(member,MailCommandHandler.option_info[opt]): - value = "on" - checked = 1 + longest = 0 + # Now populate the rows + for addr in members: + link = Link(mlist.GetOptionsURL(addr, obscure=1), + mlist.GetUserSubscribedAddress(addr)) +# name = TextBox(addr + '_realname', 'NOT YET IMPLEMENTED', size=longest) + cells = [link.Format() + '<br>' + + #name.Format() + '\n' + + Hidden('user', urllib.quote(addr)).Format(), + Center(CheckBox(addr + '_subscribed', 'on', 1).Format()), + ] + for opt in ('hide', 'nomail', 'ack', 'notmetoo'): + if mlist.GetUserOption(addr, MailCommandHandler.option_info[opt]): + value = 'on' + check = 1 else: - value = "off" + value = 'off' checked = 0 - box = CheckBox("%s_%s" % (member, opt), value, checked) - cells.append(Center(box.Format())) - if mlist.members.has_key(member): - cells.append(Center(CheckBox(member + "_digest", - "off", 0).Format())) + box = CheckBox('%s_%s' % (addr, opt), value, checked) + cells.append(Center(box).Format()) + if mlist.members.has_key(addr): + cells.append(Center(CheckBox(addr + '_digest', 'off', 0).Format())) else: - cells.append(Center(CheckBox(member + "_digest", - "on", 1).Format())) - if mlist.GetUserOption(member,MailCommandHandler.option_info['plain']): + cells.append(Center(CheckBox(addr + '_digest', 'on', 1).Format())) + if mlist.GetUserOption(addr, MailCommandHandler.option_info['plain']): value = 'on' checked = 1 else: value = 'off' checked = 0 - cells.append(Center(CheckBox('%s_plain' % member, value, checked))) - user_table.AddRow(cells) - - # format preferred user's language - pl = mlist.GetPreferredLanguage(member) - ListLangs = mlist.GetAvailableLanguages() - LangDescr = map(_, map(Utils.GetLanguageDescr, ListLangs)) + cells.append(Center(CheckBox('%s_plain' % addr, value, checked))) + # User's preferred language + langpref = mlist.GetPreferredLanguage(addr) + langs = mlist.GetAvailableLanguages() + langdescs = [_(Utils.GetLanguageDescr(lang)) for lang in langs] try: - selected = ListLangs.index(pl) - except: + selected = langs.index(langpref) + except ValueError: selected = 0 - cells.append(Center(SelectOptions(member + '_language' , ListLangs, - LangDescr, selected).Format())) - container.AddItem(Center(user_table)) + cells.append(Center(SelectOptions(addr + '_language', langs, + langdescs, selected)).Format()) + usertable.AddRow(cells) + # Add the usertable and a legend + container.AddItem(Center(usertable)) legend = UnorderedList() legend.AddItem(_('<b>subscr</b> -- Is the member subscribed?')) legend.AddItem( @@ -701,32 +790,83 @@ def membership_options(mlist, cgidata): text digests? (otherwise, MIME)''')) legend.AddItem(_("<b>language</b> -- Language preferred by the user")) container.AddItem(legend.Format()) - container.AddItem(footer) - t = Table(width="90%") - t.AddRow([Center(Header(4, _("Mass Subscribe Members")))]) - t.AddCellInfo(t.GetCurrentRowIndex(), - t.GetCurrentCellIndex(), - bgcolor="#cccccc", colspan=8) - if mlist.send_welcome_msg: - nochecked = 0 - yeschecked = 1 - else: - nochecked = 1 - yeschecked = 0 - t.AddRow([("<b>1.</b>" + _("Send Welcome message to this batch? ") - + RadioButton("send_welcome_msg_to_this_batch", 0, - nochecked).Format() - + _(" no ") - + RadioButton("send_welcome_msg_to_this_batch", 1, - yeschecked).Format() - + _(" yes "))]) - t.AddRow(["<b>2.</b>" + _("Enter one address per line:") + "<p>"]) - container.AddItem(Center(t)) - container.AddItem(Center(TextArea(name='subscribees', - rows=10,cols=60,wrap=None))) + + # There may be additional chunks + if chunkindex is not None: + buttons = [] + url = mlist.GetScriptURL('admin') + '/members?letter=%s&' % bucket + footer = _('''<p><em>To view more members, click on the appropriate + range listed below:</em>''') + chunkmembers = buckets[bucket] + last = len(chunkmembers) + for i in range(numchunks): + if i == chunkindex: + continue + start = chunkmembers[i*chunksz] + end = chunkmembers[min((i+1)*chunksz, last)-1] + link = Link(url + 'chunk=%d' % i, _('from %(start)s to %(end)s')) + buttons.append(link) + buttons = UnorderedList(*buttons) + container.AddItem(footer + buttons.Format() + '<p>') + # Search for member + container.AddItem( + _('Find members by regular expression:') + + TextBox('findmember', value=regexp, size='50%').Format() + + SubmitButton('findmember_btn', 'Search...').Format()) return container +def mass_subscribe(mlist, container): + # MASS SUBSCRIBE + t = Table(width='90%') + # Ask whether to send a welcome message and/or to notify the admin + t.AddRow([_('Send welcome message to this batch? ') + + RadioButton('send_welcome_msg_to_this_batch', 0, + not mlist.send_welcome_msg).Format() + + _(' no ') + + RadioButton('send_welcome_msg_to_this_batch', 1, + mlist.send_welcome_msg).Format() + + _(' yes ')]) + t.AddRow([_('Send notifications to the list owner? ') + + RadioButton('send_notifications_to_list_owner', 0, + not mlist.admin_notify_mchanges).Format() + + _(' no ') + + RadioButton('send_notifications_to_list_owner', 1, + mlist.admin_notify_mchanges).Format() + + _(' yes ')]) + t.AddRow([Italic(_('Enter one address per line below...')).Format() + + '<br>']) + t.AddRow([Center(TextArea(name='subscribees', + rows=10, cols='100%', wrap=None))]) + t.AddRow([Italic(_('...or specify a file to upload:'))]) + t.AddRow([FileUpload('subscribees_upload', cols='50').Format()]) + container.AddItem(Center(t)) + + +def mass_remove(mlist, container): + # MASS UNSUBSCRIBE + t = Table(width='90%') + t.AddRow([_('Send unsubscription acknowledgement to the user? ') + + RadioButton('send_unsub_ack_to_this_batch', 0, 1).Format() + + _(' no ') + + RadioButton('send_unsub_ack_to_this_batch', 1, 0).Format() + +_(' yes ')]) + t.AddRow([_('Send notifications to the list owner? ') + + RadioButton('send_unsub_notifications_to_list_owner', 0, + not mlist.admin_notify_mchanges).Format() + + _(' no ') + + RadioButton('send_unsub_notifications_to_list_owner', 1, + mlist.admin_notify_mchanges).Format() + + _(' yes ')]) + t.AddRow([Italic(_('Enter one address per line below...')).Format() + + '<br>']) + t.AddRow([Center(TextArea(name='unsubscribees', + rows=10, cols='100%', wrap=None))]) + t.AddRow([Italic(_('...or specify a file to upload:'))]) + t.AddRow([FileUpload('unsubscribees_upload', cols='50').Format()]) + container.AddItem(Center(t)) + + def password_inputs(): change_pw_table = Table(bgcolor="#99cccc", border=0, @@ -818,36 +958,37 @@ def get_valid_value(mlist, prop, my_type, val, dependant): -def change_options(mlist, category, cgi_info, document): +def change_options(mlist, category, cgidata, doc): confirmed = 0 - if cgi_info.has_key('newpw'): - if cgi_info.has_key('confirmpw'): - if cgi_info.has_key('adminpw') and cgi_info['adminpw'].value: + if cgidata.has_key('newpw'): + if cgidata.has_key('confirmpw'): + if cgidata.has_key('adminpw') and cgidata['adminpw'].value: try: - mlist.ConfirmAdminPassword(cgi_info['adminpw'].value) + mlist.ConfirmAdminPassword(cgidata['adminpw'].value) confirmed = 1 except Errors.MMBadPasswordError: - add_error_message(document, - _('Incorrect administrator password'), - tag='Error: ') + add_error_message(doc, + _('Incorrect administrator password'), + tag='Error: ') if confirmed: - new = cgi_info['newpw'].value.strip() - confirm = cgi_info['confirmpw'].value.strip() + new = cgidata['newpw'].value.strip() + confirm = cgidata['confirmpw'].value.strip() if new == '' and confirm == '': - add_error_message(document, - _('Empty admin passwords are not allowed'), - tag='Error: ') + add_error_message( + doc, + _('Empty admin passwords are not allowed'), + tag='Error: ') elif new == confirm: mlist.password = sha.new(new).hexdigest() # Re-authenticate (to set new cookie) mlist.WebAuthenticate(password=new, cookie='admin') else: - add_error_message(document, _('Passwords did not match'), - tag='Error: ') + add_error_message(doc, _('Passwords did not match'), + tag='Error: ') else: - add_error_message(document, - _('You must type in your new password twice'), - tag='Error: ') + add_error_message(doc, + _('You must type in your new password twice'), + tag='Error: ') # # for some reason, the login page mangles important values for the list # such as .real_name so we only process these changes if the category @@ -855,29 +996,29 @@ def change_options(mlist, category, cgi_info, document): # -scott 19980515 # if category != 'members' and \ - not cgi_info.has_key("request_login") and \ - len(cgi_info.keys()) > 1: + not cgidata.has_key("request_login") and \ + len(cgidata.keys()) > 1: # then - if cgi_info.has_key("subscribe_policy"): + if cgidata.has_key("subscribe_policy"): if not mm_cfg.ALLOW_OPEN_SUBSCRIBE: # # we have to add one to the value because the # page didn't present an open list as an option # - page_setting = int(cgi_info["subscribe_policy"].value) - cgi_info["subscribe_policy"].value = str(page_setting + 1) + page_setting = int(cgidata["subscribe_policy"].value) + cgidata["subscribe_policy"].value = str(page_setting + 1) opt_list = get_config_options(mlist, category) for item in opt_list: if type(item) <> types.TupleType or len(item) < 5: continue property, kind, args, deps, desc = item[0:5] - if cgi_info.has_key(property+'_upload') and \ - cgi_info[property+'_upload'].value: - val = cgi_info[property+'_upload'].value - elif not cgi_info.has_key(property): + if cgidata.has_key(property+'_upload') and \ + cgidata[property+'_upload'].value: + val = cgidata[property+'_upload'].value + elif not cgidata.has_key(property): continue else: - val = cgi_info[property].value + val = cgidata[property].value value = get_valid_value(mlist, property, kind, val, deps) # # This is an ugly, ugly hack @@ -897,7 +1038,7 @@ def change_options(mlist, category, cgi_info, document): if property == 'real_name' and \ value.lower() <> mlist._internal_name.lower(): # then don't install this value. - document.AddItem(_("""<p><b>real_name</b> attribute not + doc.AddItem(_("""<p><b>real_name</b> attribute not changed! It must differ from the list's name by case only.<p>""")) continue @@ -906,15 +1047,19 @@ def change_options(mlist, category, cgi_info, document): if property == 'preferred_language': i18n.set_language(value) setattr(mlist, property, value) - # - # mass subscription processing for members category - # - if cgi_info.has_key('subscribees'): - name_text = cgi_info['subscribees'].value - name_text = name_text.replace('\r', '') - names = filter(None, [unquote(n.strip()) for n in name_text.split(NL)]) + # mass subscription, removal processing for members category + subscriptions = '' + if cgidata.has_key('subscribees'): + subscriptions += cgidata['subscribees'].value + if cgidata.has_key('subscribees_upload') and \ + cgidata['subscribees_upload'].value: + subscriptions += cgidata['subscribees_upload'].value + if subscriptions: + subscriptions.replace('\r', '') + names = filter(None, + [unquote(n.strip()) for n in subscriptions.split(NL)]) send_welcome_msg = int( - cgi_info["send_welcome_msg_to_this_batch"].value) + cgidata['send_welcome_msg_to_this_batch'].value) digest = 0 if not mlist.digestable: digest = 0 @@ -923,7 +1068,7 @@ def change_options(mlist, category, cgi_info, document): subscribe_errors = [] subscribe_success = [] result = mlist.ApprovedAddMembers(names, None, - digest, None, send_welcome_msg) + digest, None, send_welcome_msg) for name in result.keys(): if result[name] is None: subscribe_success.append(name) @@ -937,25 +1082,59 @@ def change_options(mlist, category, cgi_info, document): if name == '': name = '<blank line>' subscribe_errors.append( - (name, _("Bad/Invalid email address"))) + (name, _('Bad/Invalid email address'))) elif e is Errors.MMHostileAddress: subscribe_errors.append( - (name, _("Hostile Address (illegal characters)"))) + (name, _('Hostile Address (illegal characters)'))) if subscribe_success: - document.AddItem(Header(5, _("Successfully Subscribed:"))) - document.AddItem(apply(UnorderedList, tuple((subscribe_success)))) - document.AddItem("<p>") + doc.AddItem(Header(5, _('Successfully Subscribed:'))) + doc.AddItem(UnorderedList(*subscribe_success)) + doc.AddItem('<p>') # ApprovedAddMembers will already have saved the list for us. if subscribe_errors: - document.AddItem(Header(5, _("Error Subscribing:"))) - items = map(lambda x: "%s -- %s" % (x[0], x[1]), subscribe_errors) - document.AddItem(apply(UnorderedList, tuple((items)))) - document.AddItem("<p>") + doc.AddItem(Header(5, _('Error Subscribing:'))) + items = ['%s -- %s' % (x0, x1) for x0, x1 in subscribe_errors] + doc.AddItem(UnorderedList(*items)) + doc.AddItem('<p>') + # Unsubscriptions + removals = '' + if cgidata.has_key('unsubscribees'): + removals += cgidata['unsubscribees'].value + if cgidata.has_key('unsubscribees_upload') and \ + cgidata['unsubscribees_upload'].value: + removals += cgidata['unsubscribees_upload'].value + if removals: + removals.replace('\r', '') + names = filter(None, [unquote(n.strip()) for n in removals.split(NL)]) + send_unsub_notifications = int( + cgidata['send_unsub_notifications_to_list_owner'].value) + userack = int( + cgidata['send_unsub_ack_to_this_batch'].value) + unsubscribe_errors = [] + unsubscribe_success = [] + for addr in names: + try: + mlist.DeleteMember(addr, whence='admin mass unsub', + admin_notif=send_unsub_notifications, + userack=userack) + unsubscribe_success.append(addr) + except Errors.MMNoSuchUserError: + unsubscribe_errors.append(addr) + if unsubscribe_success: + doc.AddItem(Header(5, _('Successfully Unsubscribed:'))) + doc.AddItem(UnorderedList(*unsubscribe_success)) + doc.AddItem('<p>') + # ApprovedAddMembers will already have saved the list for us. + if unsubscribe_errors: + doc.AddItem(Header(3, Bold(FontAttr( + _('Cannot unsubscribe non-members:'), + color='#ff0000', size='+2')).Format())) + doc.AddItem(UnorderedList(*unsubscribe_errors)) + doc.AddItem('<p>') # # do the user options for members category - # - if cgi_info.has_key('user'): - user = cgi_info["user"] + if cgidata.has_key('user'): + user = cgidata["user"] if type(user) is types.ListType: users = [] for ui in range(len(user)): @@ -964,13 +1143,13 @@ def change_options(mlist, category, cgi_info, document): users = [urllib.unquote(user.value)] errors = [] for user in users: - if not cgi_info.has_key('%s_subscribed' % (user)): + if not cgidata.has_key('%s_subscribed' % (user)): try: mlist.DeleteMember(user) except Errors.MMNoSuchUserError: errors.append((user, _('Not subscribed'))) continue - value = cgi_info.has_key('%s_digest' % user) + value = cgidata.has_key('%s_digest' % user) try: mlist.SetUserDigest(user, value, force=1) except (Errors.MMNotAMemberError, @@ -978,23 +1157,23 @@ def change_options(mlist, category, cgi_info, document): Errors.MMAlreadyUndigested): pass - if cgi_info.has_key(user+'_language'): - newlang = cgi_info[user+'_language'].value + if cgidata.has_key(user+'_language'): + newlang = cgidata[user+'_language'].value oldlang = mlist.GetPreferredLanguage(user) if newlang <> oldlang: mlist.SetPreferredLanguage(user, newlang) for opt in ("hide", "nomail", "ack", "notmetoo", "plain"): opt_code = MailCommandHandler.option_info[opt] - if cgi_info.has_key("%s_%s" % (user, opt)): + if cgidata.has_key("%s_%s" % (user, opt)): mlist.SetUserOption(user, opt_code, 1, save_list=0) else: mlist.SetUserOption(user, opt_code, 0, save_list=0) if errors: - document.AddItem(Header(5, _("Error Unsubscribing:"))) + doc.AddItem(Header(5, _("Error Unsubscribing:"))) items = ['%s -- %s' % (x[0], x[1]) for x in errors] - document.AddItem(apply(UnorderedList, tuple((items)))) - document.AddItem("<p>") + doc.AddItem(apply(UnorderedList, tuple((items)))) + doc.AddItem("<p>") |
