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 | |
As if this file wasn't enough of an ugly hack ;) -- significant
redesign of the admin page. From the NEWS file:
- Redesign of the membership management page. The page is now
split into three subcategories (Membership List, Mass
Subscription, and Mass Removal). The Membership List
subcategory now supports searching for member addresses by
regular expression, and if necessary, it groups member addresses
first alphabetically, and then by chunks.
Mass Subscription and Mass Removal now alternatively support
file upload, with one address per line.
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>") |
