diff options
| author | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
| commit | a1c73f6c305c7f74987d99855ba59d8fa823c253 (patch) | |
| tree | 65696889450862357c9e05c8e9a589f1bdc074ac /Mailman/Cgi/admindb.py | |
| parent | 3f31f8cce369529d177cfb5a7c66346ec1e12130 (diff) | |
| download | mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.gz mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.zst mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.zip | |
Diffstat (limited to 'Mailman/Cgi/admindb.py')
| -rw-r--r-- | Mailman/Cgi/admindb.py | 813 |
1 files changed, 0 insertions, 813 deletions
diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py deleted file mode 100644 index 4791c485f..000000000 --- a/Mailman/Cgi/admindb.py +++ /dev/null @@ -1,813 +0,0 @@ -# Copyright (C) 1998-2008 by the Free Software Foundation, Inc. -# -# This program 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 2 -# of the License, or (at your option) any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -"""Produce and process the pending-approval items for a list.""" - -import os -import cgi -import sys -import time -import email -import errno -import logging - -from urllib import quote_plus, unquote_plus - -from Mailman import Errors -from Mailman import MailList -from Mailman import Message -from Mailman import Utils -from Mailman import i18n -from Mailman.Cgi import Auth -from Mailman.Handlers.Moderate import ModeratedMemberPost -from Mailman.ListAdmin import readMessage -from Mailman.configuration import config -from Mailman.htmlformat import * -from Mailman.interfaces import RequestType - -EMPTYSTRING = '' -NL = '\n' - -# Set up i18n. Until we know which list is being requested, we use the -# server's default. -_ = i18n._ -i18n.set_language(config.DEFAULT_SERVER_LANGUAGE) - -EXCERPT_HEIGHT = 10 -EXCERPT_WIDTH = 76 - -log = logging.getLogger('mailman.error') - - - -def helds_by_sender(mlist): - bysender = {} - requests = config.db.get_list_requests(mlist) - for request in requests.of_type(RequestType.held_message): - key, data = requests.get_request(request.id) - sender = data.get('sender') - assert sender is not None, ( - 'No sender for held message: %s' % request.id) - bysender.setdefault(sender, []).append(request.id) - return bysender - - -def hacky_radio_buttons(btnname, labels, values, defaults, spacing=3): - # We can't use a RadioButtonArray here because horizontal placement can be - # confusing to the user and vertical placement takes up too much - # real-estate. This is a hack! - space = ' ' * spacing - btns = Table(cellspacing='5', cellpadding='0') - btns.AddRow([space + text + space for text in labels]) - btns.AddRow([Center(RadioButton(btnname, value, default)) - for value, default in zip(values, defaults)]) - return btns - - - -def main(): - # Figure out which list is being requested - parts = Utils.GetPathPieces() - if not parts: - handle_no_list() - return - - listname = parts[0].lower() - try: - mlist = MailList.MailList(listname, lock=0) - except Errors.MMListError, e: - # Avoid cross-site scripting attacks - safelistname = Utils.websafe(listname) - handle_no_list(_('No such list <em>%(safelistname)s</em>')) - log.error('No such list "%s": %s\n', listname, e) - return - - # Now that we know which list to use, set the system's language to it. - i18n.set_language(mlist.preferred_language) - - # Make sure the user is authorized to see this page. - cgidata = cgi.FieldStorage(keep_blank_values=1) - - if not mlist.WebAuthenticate((config.AuthListAdmin, - config.AuthListModerator, - config.AuthSiteAdmin), - cgidata.getvalue('adminpw', '')): - if cgidata.has_key('adminpw'): - # This is a re-authorization attempt - msg = Bold(FontSize('+1', _('Authorization failed.'))).Format() - else: - msg = '' - Auth.loginpage(mlist, 'admindb', msg=msg) - return - - # Set up the results document - doc = Document() - doc.set_language(mlist.preferred_language) - - # See if we're requesting all the messages for a particular sender, or if - # we want a specific held message. - sender = None - msgid = None - details = None - envar = os.environ.get('QUERY_STRING') - if envar: - # POST methods, even if their actions have a query string, don't get - # put into FieldStorage's keys :-( - qs = cgi.parse_qs(envar).get('sender') - if qs and isinstance(qs, list): - sender = qs[0] - qs = cgi.parse_qs(envar).get('msgid') - if qs and isinstance(qs, list): - msgid = qs[0] - qs = cgi.parse_qs(envar).get('details') - if qs and isinstance(qs, list): - details = qs[0] - - mlist.Lock() - try: - realname = mlist.real_name - if not cgidata.keys() or cgidata.has_key('admlogin'): - # If this is not a form submission (i.e. there are no keys in the - # form) or it's a login, then we don't need to do much special. - doc.SetTitle(_('%(realname)s Administrative Database')) - elif not details: - # This is a form submission - doc.SetTitle(_('%(realname)s Administrative Database Results')) - process_form(mlist, doc, cgidata) - # Now print the results and we're done. Short circuit for when there - # are no pending requests, but be sure to save the results! - if config.db.requests.get_list_requests(mlist).count == 0: - title = _('%(realname)s Administrative Database') - doc.SetTitle(title) - doc.AddItem(Header(2, title)) - doc.AddItem(_('There are no pending requests.')) - doc.AddItem(' ') - doc.AddItem(Link(mlist.GetScriptURL('admindb'), - _('Click here to reload this page.'))) - doc.AddItem(mlist.GetMailmanFooter()) - print doc.Format() - mlist.Save() - return - - admindburl = mlist.GetScriptURL('admindb') - form = Form(admindburl) - # Add the instructions template - if details == 'instructions': - doc.AddItem(Header( - 2, _('Detailed instructions for the administrative database'))) - else: - doc.AddItem(Header( - 2, - _('Administrative requests for mailing list:') - + ' <em>%s</em>' % mlist.real_name)) - if details <> 'instructions': - form.AddItem(Center(SubmitButton('submit', _('Submit All Data')))) - requestsdb = config.db.get_list_requests(mlist) - message_count = requestsdb.count_of(RequestType.held_message) - if not (details or sender or msgid or message_count == 0): - form.AddItem(Center( - CheckBox('discardalldefersp', 0).Format() + - ' ' + - _('Discard all messages marked <em>Defer</em>') - )) - # Add a link back to the overview, if we're not viewing the overview! - adminurl = mlist.GetScriptURL('admin') - d = {'listname' : mlist.real_name, - 'detailsurl': admindburl + '?details=instructions', - 'summaryurl': admindburl, - 'viewallurl': admindburl + '?details=all', - 'adminurl' : adminurl, - 'filterurl' : adminurl + '/privacy/sender', - } - addform = 1 - if sender: - esender = Utils.websafe(sender) - d['description'] = _("all of %(esender)s's held messages.") - doc.AddItem(Utils.maketext('admindbpreamble.html', d, - raw=1, mlist=mlist)) - show_sender_requests(mlist, form, sender) - elif msgid: - d['description'] = _('a single held message.') - doc.AddItem(Utils.maketext('admindbpreamble.html', d, - raw=1, mlist=mlist)) - show_message_requests(mlist, form, msgid) - elif details == 'all': - d['description'] = _('all held messages.') - doc.AddItem(Utils.maketext('admindbpreamble.html', d, - raw=1, mlist=mlist)) - show_detailed_requests(mlist, form) - elif details == 'instructions': - doc.AddItem(Utils.maketext('admindbdetails.html', d, - raw=1, mlist=mlist)) - addform = 0 - else: - # Show a summary of all requests - doc.AddItem(Utils.maketext('admindbsummary.html', d, - raw=1, mlist=mlist)) - num = show_pending_subs(mlist, form) - num += show_pending_unsubs(mlist, form) - num += show_helds_overview(mlist, form) - addform = num > 0 - # Finish up the document, adding buttons to the form - if addform: - doc.AddItem(form) - form.AddItem('<hr>') - if not (details or sender or msgid or nomessages): - form.AddItem(Center( - CheckBox('discardalldefersp', 0).Format() + - ' ' + - _('Discard all messages marked <em>Defer</em>') - )) - form.AddItem(Center(SubmitButton('submit', _('Submit All Data')))) - doc.AddItem(mlist.GetMailmanFooter()) - print doc.Format() - # Commit all changes - mlist.Save() - finally: - mlist.Unlock() - - - -def handle_no_list(msg=''): - # Print something useful if no list was given. - doc = Document() - doc.set_language(config.DEFAULT_SERVER_LANGUAGE) - - header = _('Mailman Administrative Database Error') - doc.SetTitle(header) - doc.AddItem(Header(2, header)) - doc.AddItem(msg) - url = Utils.ScriptURL('admin') - link = Link(url, _('list of available mailing lists.')).Format() - doc.AddItem(_('You must specify a list name. Here is the %(link)s')) - doc.AddItem('<hr>') - doc.AddItem(MailmanLogo()) - print doc.Format() - - - -def show_pending_subs(mlist, form): - # Add the subscription request section - requestsdb = config.db.get_list_requests(mlist) - if requestsdb.count_of(RequestType.subscription) == 0: - return 0 - form.AddItem('<hr>') - form.AddItem(Center(Header(2, _('Subscription Requests')))) - table = Table(border=2) - table.AddRow([Center(Bold(_('Address/name'))), - Center(Bold(_('Your decision'))), - Center(Bold(_('Reason for refusal'))) - ]) - # Alphabetical order by email address - byaddrs = {} - for request in requestsdb.of_type(RequestType.subscription): - key, data = requestsdb.get_request(requst.id) - addr = data['addr'] - byaddrs.setdefault(addr, []).append(request.id) - addrs = sorted(byaddrs) - num = 0 - for addr, ids in byaddrs.items(): - # Eliminate duplicates - for id in ids[1:]: - mlist.HandleRequest(id, config.DISCARD) - id = ids[0] - key, data = requestsdb.get_request(id) - time = data['time'] - addr = data['addr'] - fullname = data['fullname'] - passwd = data['passwd'] - digest = data['digest'] - lang = data['lang'] - fullname = Utils.uncanonstr(fullname, mlist.preferred_language) - radio = RadioButtonArray(id, (_('Defer'), - _('Approve'), - _('Reject'), - _('Discard')), - values=(config.DEFER, - config.SUBSCRIBE, - config.REJECT, - config.DISCARD), - checked=0).Format() - if addr not in mlist.ban_list: - radio += '<br>' + CheckBox('ban-%d' % id, 1).Format() + \ - ' ' + _('Permanently ban from this list') - # While the address may be a unicode, it must be ascii - paddr = addr.encode('us-ascii', 'replace') - table.AddRow(['%s<br><em>%s</em>' % (paddr, fullname), - radio, - TextBox('comment-%d' % id, size=40) - ]) - num += 1 - if num > 0: - form.AddItem(table) - return num - - - -def show_pending_unsubs(mlist, form): - # Add the pending unsubscription request section - lang = mlist.preferred_language - requestsdb = config.db.get_list_requests(mlist) - if requestsdb.count_of(RequestType.unsubscription) == 0: - return 0 - table = Table(border=2) - table.AddRow([Center(Bold(_('User address/name'))), - Center(Bold(_('Your decision'))), - Center(Bold(_('Reason for refusal'))) - ]) - # Alphabetical order by email address - byaddrs = {} - for request in requestsdb.of_type(RequestType.unsubscription): - key, data = requestsdb.get_request(request.id) - addr = data['addr'] - byaddrs.setdefault(addr, []).append(request.id) - addrs = sorted(byaddrs) - num = 0 - for addr, ids in byaddrs.items(): - # Eliminate duplicates - for id in ids[1:]: - mlist.HandleRequest(id, config.DISCARD) - id = ids[0] - key, data = requestsdb.get_record(id) - addr = data['addr'] - try: - fullname = Utils.uncanonstr(mlist.getMemberName(addr), lang) - except Errors.NotAMemberError: - # They must have been unsubscribed elsewhere, so we can just - # discard this record. - mlist.HandleRequest(id, config.DISCARD) - continue - num += 1 - table.AddRow(['%s<br><em>%s</em>' % (addr, fullname), - RadioButtonArray(id, (_('Defer'), - _('Approve'), - _('Reject'), - _('Discard')), - values=(config.DEFER, - config.UNSUBSCRIBE, - config.REJECT, - config.DISCARD), - checked=0), - TextBox('comment-%d' % id, size=45) - ]) - if num > 0: - form.AddItem('<hr>') - form.AddItem(Center(Header(2, _('Unsubscription Requests')))) - form.AddItem(table) - return num - - - -def show_helds_overview(mlist, form): - # Sort the held messages by sender - bysender = helds_by_sender(mlist) - if not bysender: - return 0 - form.AddItem('<hr>') - form.AddItem(Center(Header(2, _('Held Messages')))) - # Add the by-sender overview tables - admindburl = mlist.GetScriptURL('admindb') - table = Table(border=0) - form.AddItem(table) - senders = bysender.keys() - senders.sort() - for sender in senders: - qsender = quote_plus(sender) - esender = Utils.websafe(sender) - senderurl = admindburl + '?sender=' + qsender - # The encompassing sender table - stable = Table(border=1) - stable.AddRow([Center(Bold(_('From:')).Format() + esender)]) - stable.AddCellInfo(stable.GetCurrentRowIndex(), 0, colspan=2) - left = Table(border=0) - left.AddRow([_('Action to take on all these held messages:')]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - btns = hacky_radio_buttons( - 'senderaction-' + qsender, - (_('Defer'), _('Accept'), _('Reject'), _('Discard')), - (config.DEFER, config.APPROVE, config.REJECT, config.DISCARD), - (1, 0, 0, 0)) - left.AddRow([btns]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - left.AddRow([ - CheckBox('senderpreserve-' + qsender, 1).Format() + - ' ' + - _('Preserve messages for the site administrator') - ]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - left.AddRow([ - CheckBox('senderforward-' + qsender, 1).Format() + - ' ' + - _('Forward messages (individually) to:') - ]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - left.AddRow([ - TextBox('senderforwardto-' + qsender, - value=mlist.GetOwnerEmail()) - ]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - # If the sender is a member and the message is being held due to a - # moderation bit, give the admin a chance to clear the member's mod - # bit. If this sender is not a member and is not already on one of - # the sender filters, then give the admin a chance to add this sender - # to one of the filters. - if mlist.isMember(sender): - if mlist.getMemberOption(sender, config.Moderate): - left.AddRow([ - CheckBox('senderclearmodp-' + qsender, 1).Format() + - ' ' + - _("Clear this member's <em>moderate</em> flag") - ]) - else: - left.AddRow( - [_('<em>The sender is now a member of this list</em>')]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - elif sender not in (mlist.accept_these_nonmembers + - mlist.hold_these_nonmembers + - mlist.reject_these_nonmembers + - mlist.discard_these_nonmembers): - left.AddRow([ - CheckBox('senderfilterp-' + qsender, 1).Format() + - ' ' + - _('Add <b>%(esender)s</b> to one of these sender filters:') - ]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - btns = hacky_radio_buttons( - 'senderfilter-' + qsender, - (_('Accepts'), _('Holds'), _('Rejects'), _('Discards')), - (config.ACCEPT, config.HOLD, config.REJECT, config.DISCARD), - (0, 0, 0, 1)) - left.AddRow([btns]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - if sender not in mlist.ban_list: - left.AddRow([ - CheckBox('senderbanp-' + qsender, 1).Format() + - ' ' + - _("""Ban <b>%(esender)s</b> from ever subscribing to this - mailing list""")]) - left.AddCellInfo(left.GetCurrentRowIndex(), 0, colspan=2) - right = Table(border=0) - right.AddRow([ - _("""Click on the message number to view the individual - message, or you can """) + - Link(senderurl, _('view all messages from %(esender)s')).Format() - ]) - right.AddCellInfo(right.GetCurrentRowIndex(), 0, colspan=2) - right.AddRow([' ', ' ']) - counter = 1 - for id in bysender[sender]: - key, data = requestsdb.get_record(id) - ptime = data['ptime'] - sender = data['sender'] - subject = data['subject'] - reason = data['reason'] - filename = data['filename'] - msgdata = data['msgdata'] - # BAW: This is really the size of the message pickle, which should - # be close, but won't be exact. Sigh, good enough. - try: - size = os.path.getsize(os.path.join(config.DATA_DIR, filename)) - except OSError, e: - if e.errno <> errno.ENOENT: raise - # This message must have gotten lost, i.e. it's already been - # handled by the time we got here. - mlist.HandleRequest(id, config.DISCARD) - continue - dispsubj = Utils.oneline( - subject, Utils.GetCharSet(mlist.preferred_language)) - t = Table(border=0) - t.AddRow([Link(admindburl + '?msgid=%d' % id, '[%d]' % counter), - Bold(_('Subject:')), - Utils.websafe(dispsubj) - ]) - t.AddRow([' ', Bold(_('Size:')), str(size) + _(' bytes')]) - if reason: - reason = _(reason) - else: - reason = _('not available') - t.AddRow([' ', Bold(_('Reason:')), reason]) - # Include the date we received the message, if available - when = msgdata.get('received_time') - if when: - t.AddRow([' ', Bold(_('Received:')), - time.ctime(when)]) - counter += 1 - right.AddRow([t]) - stable.AddRow([left, right]) - table.AddRow([stable]) - return 1 - - - -def show_sender_requests(mlist, form, sender): - bysender = helds_by_sender(mlist) - if not bysender: - return - sender_ids = bysender.get(sender) - if sender_ids is None: - # BAW: should we print an error message? - return - total = len(sender_ids) - requestsdb = config.db.get_list_requests(mlist) - for i, id in enumerate(sender_ids): - key, data = requestsdb.get_record(id) - show_post_requests(mlist, id, data, total, count + 1, form) - - - -def show_message_requests(mlist, form, id): - requestdb = config.db.get_list_requests(mlist) - try: - id = int(id) - info = requestdb.get_record(id) - except (ValueError, KeyError): - # BAW: print an error message? - return - show_post_requests(mlist, id, info, 1, 1, form) - - - -def show_detailed_requests(mlist, form): - requestsdb = config.db.get_list_requests(mlist) - total = requestsdb.count_of(RequestType.held_message) - all = requestsdb.of_type(RequestType.held_message) - for i, request in enumerate(all): - key, data = requestdb.get_request(request.id) - show_post_requests(mlist, request.id, data, total, i + 1, form) - - - -def show_post_requests(mlist, id, info, total, count, form): - # For backwards compatibility with pre 2.0beta3 - if len(info) == 5: - ptime, sender, subject, reason, filename = info - msgdata = {} - else: - ptime, sender, subject, reason, filename, msgdata = info - form.AddItem('<hr>') - # Header shown on each held posting (including count of total) - msg = _('Posting Held for Approval') - if total <> 1: - msg += _(' (%(count)d of %(total)d)') - form.AddItem(Center(Header(2, msg))) - # We need to get the headers and part of the textual body of the message - # being held. The best way to do this is to use the email Parser to get - # an actual object, which will be easier to deal with. We probably could - # just do raw reads on the file. - try: - msg = readMessage(os.path.join(config.DATA_DIR, filename)) - except IOError, e: - if e.errno <> errno.ENOENT: - raise - form.AddItem(_('<em>Message with id #%(id)d was lost.')) - form.AddItem('<p>') - # BAW: kludge to remove id from requests.db. - try: - mlist.HandleRequest(id, config.DISCARD) - except Errors.LostHeldMessage: - pass - return - except email.Errors.MessageParseError: - form.AddItem(_('<em>Message with id #%(id)d is corrupted.')) - # BAW: Should we really delete this, or shuttle it off for site admin - # to look more closely at? - form.AddItem('<p>') - # BAW: kludge to remove id from requests.db. - try: - mlist.HandleRequest(id, config.DISCARD) - except Errors.LostHeldMessage: - pass - return - # Get the header text and the message body excerpt - lines = [] - chars = 0 - # A negative value means, include the entire message regardless of size - limit = config.ADMINDB_PAGE_TEXT_LIMIT - for line in email.Iterators.body_line_iterator(msg): - lines.append(line) - chars += len(line) - if chars > limit > 0: - break - # Negative values mean display the entire message, regardless of size - if limit > 0: - body = EMPTYSTRING.join(lines)[:config.ADMINDB_PAGE_TEXT_LIMIT] - else: - body = EMPTYSTRING.join(lines) - # Get message charset and try encode in list charset - mcset = msg.get_param('charset', 'us-ascii').lower() - lcset = Utils.GetCharSet(mlist.preferred_language) - if mcset <> lcset: - try: - body = unicode(body, mcset).encode(lcset) - except (LookupError, UnicodeError, ValueError): - pass - hdrtxt = NL.join(['%s: %s' % (k, v) for k, v in msg.items()]) - hdrtxt = Utils.websafe(hdrtxt) - # Okay, we've reconstituted the message just fine. Now for the fun part! - t = Table(cellspacing=0, cellpadding=0, width='100%') - t.AddRow([Bold(_('From:')), sender]) - row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() - t.AddCellInfo(row, col-1, align='right') - t.AddRow([Bold(_('Subject:')), - Utils.websafe(Utils.oneline(subject, lcset))]) - t.AddCellInfo(row+1, col-1, align='right') - t.AddRow([Bold(_('Reason:')), _(reason)]) - t.AddCellInfo(row+2, col-1, align='right') - when = msgdata.get('received_time') - if when: - t.AddRow([Bold(_('Received:')), time.ctime(when)]) - t.AddCellInfo(row+2, col-1, align='right') - # We can't use a RadioButtonArray here because horizontal placement can be - # confusing to the user and vertical placement takes up too much - # real-estate. This is a hack! - buttons = Table(cellspacing="5", cellpadding="0") - buttons.AddRow(map(lambda x, s=' '*5: s+x+s, - (_('Defer'), _('Approve'), _('Reject'), _('Discard')))) - buttons.AddRow([Center(RadioButton(id, config.DEFER, 1)), - Center(RadioButton(id, config.APPROVE, 0)), - Center(RadioButton(id, config.REJECT, 0)), - Center(RadioButton(id, config.DISCARD, 0)), - ]) - t.AddRow([Bold(_('Action:')), buttons]) - t.AddCellInfo(row+3, col-1, align='right') - t.AddRow([' ', - CheckBox('preserve-%d' % id, 'on', 0).Format() + - ' ' + _('Preserve message for site administrator') - ]) - t.AddRow([' ', - CheckBox('forward-%d' % id, 'on', 0).Format() + - ' ' + _('Additionally, forward this message to: ') + - TextBox('forward-addr-%d' % id, size=47, - value=mlist.GetOwnerEmail()).Format() - ]) - notice = msgdata.get('rejection_notice', _('[No explanation given]')) - t.AddRow([ - Bold(_('If you reject this post,<br>please explain (optional):')), - TextArea('comment-%d' % id, rows=4, cols=EXCERPT_WIDTH, - text = Utils.wrap(_(notice), column=80)) - ]) - row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() - t.AddCellInfo(row, col-1, align='right') - t.AddRow([Bold(_('Message Headers:')), - TextArea('headers-%d' % id, hdrtxt, - rows=EXCERPT_HEIGHT, cols=EXCERPT_WIDTH, readonly=1)]) - row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() - t.AddCellInfo(row, col-1, align='right') - t.AddRow([Bold(_('Message Excerpt:')), - TextArea('fulltext-%d' % id, Utils.websafe(body), - rows=EXCERPT_HEIGHT, cols=EXCERPT_WIDTH, readonly=1)]) - t.AddCellInfo(row+1, col-1, align='right') - form.AddItem(t) - form.AddItem('<p>') - - - -def process_form(mlist, doc, cgidata): - senderactions = {} - # Sender-centric actions - for k in cgidata.keys(): - for prefix in ('senderaction-', 'senderpreserve-', 'senderforward-', - 'senderforwardto-', 'senderfilterp-', 'senderfilter-', - 'senderclearmodp-', 'senderbanp-'): - if k.startswith(prefix): - action = k[:len(prefix)-1] - sender = unquote_plus(k[len(prefix):]) - value = cgidata.getvalue(k) - senderactions.setdefault(sender, {})[action] = value - # discard-all-defers - try: - discardalldefersp = cgidata.getvalue('discardalldefersp', 0) - except ValueError: - discardalldefersp = 0 - for sender in senderactions.keys(): - actions = senderactions[sender] - # Handle what to do about all this sender's held messages - try: - action = int(actions.get('senderaction', config.DEFER)) - except ValueError: - action = config.DEFER - if action == config.DEFER and discardalldefersp: - action = config.DISCARD - if action in (config.DEFER, config.APPROVE, - config.REJECT, config.DISCARD): - preserve = actions.get('senderpreserve', 0) - forward = actions.get('senderforward', 0) - forwardaddr = actions.get('senderforwardto', '') - comment = _('No reason given') - bysender = helds_by_sender(mlist) - for id in bysender.get(sender, []): - try: - mlist.HandleRequest(id, action, comment, preserve, - forward, forwardaddr) - except (KeyError, Errors.LostHeldMessage): - # That's okay, it just means someone else has already - # updated the database while we were staring at the page, - # so just ignore it - continue - # Now see if this sender should be added to one of the nonmember - # sender filters. - if actions.get('senderfilterp', 0): - try: - which = int(actions.get('senderfilter')) - except ValueError: - # Bogus form - which = 'ignore' - if which == config.ACCEPT: - mlist.accept_these_nonmembers.append(sender) - elif which == config.HOLD: - mlist.hold_these_nonmembers.append(sender) - elif which == config.REJECT: - mlist.reject_these_nonmembers.append(sender) - elif which == config.DISCARD: - mlist.discard_these_nonmembers.append(sender) - # Otherwise, it's a bogus form, so ignore it - # And now see if we're to clear the member's moderation flag. - if actions.get('senderclearmodp', 0): - try: - mlist.setMemberOption(sender, config.Moderate, 0) - except Errors.NotAMemberError: - # This person's not a member any more. Oh well. - pass - # And should this address be banned? - if actions.get('senderbanp', 0): - if sender not in mlist.ban_list: - mlist.ban_list.append(sender) - # Now, do message specific actions - banaddrs = [] - erroraddrs = [] - for k in cgidata.keys(): - formv = cgidata[k] - if isinstance(formv, list): - continue - try: - v = int(formv.value) - request_id = int(k) - except ValueError: - continue - if v not in (config.DEFER, config.APPROVE, config.REJECT, - config.DISCARD, config.SUBSCRIBE, config.UNSUBSCRIBE, - config.ACCEPT, config.HOLD): - continue - # Get the action comment and reasons if present. - commentkey = 'comment-%d' % request_id - preservekey = 'preserve-%d' % request_id - forwardkey = 'forward-%d' % request_id - forwardaddrkey = 'forward-addr-%d' % request_id - bankey = 'ban-%d' % request_id - # Defaults - comment = _('[No reason given]') - preserve = 0 - forward = 0 - forwardaddr = '' - if cgidata.has_key(commentkey): - comment = cgidata[commentkey].value - if cgidata.has_key(preservekey): - preserve = cgidata[preservekey].value - if cgidata.has_key(forwardkey): - forward = cgidata[forwardkey].value - if cgidata.has_key(forwardaddrkey): - forwardaddr = cgidata[forwardaddrkey].value - # Should we ban this address? Do this check before handling the - # request id because that will evict the record. - requestsdb = config.db.get_list_requests(mlist) - if cgidata.getvalue(bankey): - key, data = requestsdb.get_record(request_id) - sender = data['sender'] - if sender not in mlist.ban_list: - mlist.ban_list.append(sender) - # Handle the request id - try: - mlist.HandleRequest(request_id, v, comment, - preserve, forward, forwardaddr) - except (KeyError, Errors.LostHeldMessage): - # That's okay, it just means someone else has already updated the - # database while we were staring at the page, so just ignore it - continue - except Errors.MMAlreadyAMember, v: - erroraddrs.append(v) - except Errors.MembershipIsBanned, pattern: - data = requestsdb.get_record(request_id) - sender = data['sender'] - banaddrs.append((sender, pattern)) - # save the list and print the results - doc.AddItem(Header(2, _('Database Updated...'))) - if erroraddrs: - for addr in erroraddrs: - doc.AddItem(`addr` + _(' is already a member') + '<br>') - if banaddrs: - for addr, patt in banaddrs: - doc.AddItem(_('%(addr)s is banned (matched: %(patt)s)') + '<br>') |
