summaryrefslogtreecommitdiff
path: root/Mailman/Cgi/admin.py
diff options
context:
space:
mode:
Diffstat (limited to 'Mailman/Cgi/admin.py')
-rw-r--r--Mailman/Cgi/admin.py696
1 files changed, 374 insertions, 322 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index 15179a994..9809940ee 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -30,201 +30,215 @@ from Mailman import Utils
from Mailman import MailList
from Mailman import Errors
from Mailman import MailCommandHandler
+from Mailman import i18n
from Mailman.htmlformat import *
from Mailman.Cgi import Auth
from Mailman.Logging.Syslog import syslog
-CATEGORIES = []
+# Mark, but don't translate yet
+def _(s): return s
+
+CATEGORIES = [('general', _('General Options')),
+ ('members', _('Membership Management')),
+ ('privacy', _('Privacy Options')),
+ ('nondigest', _('Regular-member (non-digest) Options')),
+ ('digest', _('Digest-member Options')),
+ ('bounce', _('Bounce Options')),
+ ('archive', _('Archival Options')),
+ ('gateway', _('Mail-News and News-Mail gateways')),
+ ]
+
+
+# Set up i18n
+_ = i18n._
+i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
NL = '\n'
def main():
- """Process and produce list options form.
-
- CGI input indicates that we're returning from submission of some new
- settings, which is processed before producing the new version.
-
- """
global CATEGORIES
- doc = Document()
+
+ # Try to find out which list is being administered
parts = Utils.GetPathPieces()
if not parts:
- FormatAdminOverview()
+ # None, so just do the admin overview and be done with it
+ admin_overview()
return
- # get the list object
+ # Get the list object
listname = parts[0].lower()
- try:
- mlist = MailList.MailList(listname)
+ try:
+ mlist = MailList.MailList(listname, lock=0)
except Errors.MMListError, e:
- FormatAdminOverview(_('No such list <em>%s</em>') % listname)
+ admin_overview(_('No such list <em>%(listname)s</em>'))
syslog('error', 'Someone tried to access the admin interface for a '
'non-existent list: %s' % listname)
return
+ #
+ # Now that we know what list has been requested, all subsequent admin
+ # pages are shown in that list's preferred language.
+ i18n.set_language(mlist.preferred_language)
+ # If the user is not authenticated, we're done.
+ cgidata = cgi.FieldStorage(keep_blank_values=1)
try:
- if len(parts) == 1:
- category = 'general'
- category_suffix = ''
- else:
- category = parts[1]
- category_suffix = category
-
- # If the user is not authenticated, we're done.
- cgidata = cgi.FieldStorage(keep_blank_values=1)
- try:
- Auth.authenticate(mlist, cgidata)
- except Auth.NotLoggedInError, e:
- Auth.loginpage(mlist, 'admin', e.message)
- return
-
- # Is this a log-out request?
- if category == 'logout':
- print mlist.ZapCookie('admin')
- Auth.loginpage(mlist, 'admin', frontpage=1)
- return
-
- os.environ['LANG'] = mlist.preferred_language
-
- CATEGORIES = [('general', _("General Options")),
- ('members', _("Membership Management")),
- ('privacy', _("Privacy Options")),
- ('nondigest', _("Regular-member (non-digest) Options")),
- ('digest', _("Digest-member Options")),
- ('bounce', _("Bounce Options")),
- ('archive', _("Archival Options")),
- ('gateway', _("Mail-News and News-Mail gateways")),
- ]
-
- if category not in map(lambda x: x[0], CATEGORIES):
- category = 'general'
-
- # is the request for variable details?
- varhelp = None
- if cgidata.has_key('VARHELP'):
- varhelp = cgidata['VARHELP'].value
- elif cgidata.has_key('request_login') and \
- os.environ.get('QUERY_STRING'):
- # 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']).get('VARHELP')
- if qs and type(qs) == types.ListType:
- varhelp = qs[0]
- if varhelp:
- FormatOptionHelp(doc, varhelp, mlist)
- print doc.Format(bgcolor="#ffffff")
- return
-
- # BAW: This doesn't appear to do anything. The pairs variable isn't
- # used anywhere. Perhaps this was meant as some incomplete error
- # checking on the value?
- if cgidata.has_key('bounce_matching_headers'):
- pairs = mlist.parse_matching_header_opt()
-
- if len(cgidata.keys()):
- ChangeOptions(mlist, category, cgidata, doc)
+ Auth.authenticate(mlist, cgidata)
+ except Auth.NotLoggedInError, e:
+ Auth.loginpage(mlist, 'admin', e.message)
+ return
+ # Which subcategory was requested? Default is `general'
+ if len(parts) == 1:
+ category = 'general'
+ category_suffix = ''
+ else:
+ category = parts[1]
+ category_suffix = category
+ # Is this a log-out request?
+ if category == 'logout':
+ print mlist.ZapCookie('admin')
+ Auth.loginpage(mlist, 'admin', frontpage=1)
+ return
+ # Sanity check
+ if category not in [x[0] for x in CATEGORIES]:
+ category = 'general'
+ # Is the request for variable details?
+ varhelp = None
+ if cgidata.has_key('VARHELP'):
+ varhelp = cgidata['VARHELP'].value
+ elif cgidata.has_key('request_login') and os.environ.get('QUERY_STRING'):
+ # 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']).get('VARHELP')
+ if qs and type(qs) == types.ListType:
+ varhelp = qs[0]
+ if varhelp:
+ option_help(mlist, varhelp)
+ return
+ # The html page document
+ doc = Document()
+ doc.set_language(mlist.preferred_language)
+ # Now we're ready to do normal form processing. For this, though we must
+ # lock the mailing list, and everything from here on out must be wrapped
+ # in a try/except.
+ #
+ # BAW: Currently we attempt to acquire the lock with no timeout, although
+ # this could get hit by a webserver or client timeout, if there's a long
+ # or stale lock on the list. Maybe we should have a configurable timeout
+ # setting after which we'll just inform the user that the operation
+ # couldn't be performed?
+ mlist.Lock()
+ try:
+ if cgidata.keys():
+ # There are options to change
+ change_options(mlist, category, cgidata, doc)
+ # Let the list sanity check the changed values
mlist.CheckValues()
-
- # Sanity checks
+ # Additional sanity checks
if not mlist.digestable and not mlist.nondigestable:
- AddErrorMessage(doc, _('''You have turned off delivery of
- both digest and non-digest messages. This is an incompatible
- state of affairs. You must turn on either digest delivery or
- non-digest delivery or your mailing list will basically be
- unusable.'''))
+ add_error_message(
+ doc,
+ _('''You have turned off delivery of both digest and
+ non-digest messages. This is an incompatible state of
+ affairs. You must turn on either digest delivery or
+ non-digest delivery or your mailing list will basically be
+ unusable.'''))
+
if not mlist.digestable and len(mlist.GetDigestMembers()):
- AddErrorMessage(doc, _('''You have digest members,
- but digests are turned off. Those people will not receive
- mail.'''))
+ add_error_message(
+ doc,
+ _('''You have digest members, but digests are turned
+ off. Those people will not receive mail.'''))
if not mlist.nondigestable and len(mlist.GetMembers()):
- AddErrorMessage(doc, _('''You have regular list members
- but non-digestified mail is turned off. They will receive mail
- until you fix this problem.'''))
-
- FormatConfiguration(doc, mlist, category, category_suffix, cgidata)
- print doc.Format(bgcolor="#ffffff")
+ add_error_message(
+ doc,
+ _('''You have regular list members but non-digestified mail is
+ turned off. They will receive mail until you fix this
+ problem.'''))
+ # Glom up the results page and print it out
+ show_results(mlist, doc, category, category_suffix, cgidata)
+ print doc.Format(bgcolor='#ffffff')
finally:
mlist.Save()
mlist.Unlock()
-# Form Production:
-def FormatAdminOverview(error=None):
- "Present a general welcome and itemize the (public) lists."
- doc = Document()
- default_hostname = mm_cfg.DEFAULT_HOST_NAME
+def admin_overview(msg=''):
+ # Show the administrative overview page, with the list of all the lists on
+ # this host. msg is an optional error message to display at the top of
+ # the page.
+ #
+ # This page should be displayed in the server's default language, which
+ # should have already been set.
+ hostname = mm_cfg.DEFAULT_HOST_NAME
legend = _('%(default_hostname)s mailing lists - Admin Links')
+ # The html `document'
+ doc = Document()
+ doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
doc.SetTitle(legend)
-
+ # The table that will hold everything
table = Table(border=0, width="100%")
table.AddRow([Center(Header(2, legend))])
table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
colspan=2, bgcolor="#99ccff")
-
+ # Skip any mailing list that isn't advertised.
advertised = []
- names = Utils.list_names()
- names.sort()
- for n in names:
- l = MailList.MailList(n, lock=0)
- if l.advertised:
- advertised.append(l)
-
- os.environ['LANG'] = mm_cfg.DEFAULT_SERVER_LANGUAGE
-
- if error:
- greeting = FontAttr(error, color="ff5060", size="+1")
+ listnames = Utils.list_names()
+ listnames.sort()
+ for name in listnames:
+ mlist = MailList.MailList(name, lock=0)
+ if mlist.advertised:
+ advertised.append(mlist)
+ # Greeting depends on whether there was an error or not
+ if msg:
+ greeting = FontAttr(msg, color="ff5060", size="+1")
else:
greeting = _("Welcome!")
+ welcome = []
if not advertised:
- welcome_items = (greeting,
- _("<p>"
- " There currently are no publicly-advertised "),
- Link(mm_cfg.MAILMAN_URL, "mailman"),
- _(" mailing lists on %s.") % mm_cfg.DEFAULT_HOST_NAME,
- )
+ welcome.extend([
+ greeting,
+ _('<p>There currently are no publicly-advertised '),
+ Link(mm_cfg.MAILMAN_URL, _('Mailman')),
+ _(' mailing lists on %(hostname)s.'),
+ ])
else:
- welcome_items = (
+ welcome.extend([
greeting,
- _("<p>"
- " Below is the collection of publicly-advertised "),
- Link(mm_cfg.MAILMAN_URL, "mailman"),
- _(" mailing lists on %(default_hostname)s."),
- (_(' Click on a list name to visit the configuration pages'
- ' for that list.')
- )
- )
+ _('<p>Below is the collection of publicly-advertised '),
+ Link(mm_cfg.MAILMAN_URL, _('Mailman')),
+ _(' mailing lists on %(hostname)s.'),
+ _(''' Click on a list name to visit the configuration pages for
+ that list.'''),
+ ])
mailman_owner = mm_cfg.MAILMAN_OWNER
- extra = error and _('right ') or ''
- welcome_items = (welcome_items +
- (_(" To visit the administrators configuration page for"
- " an unadvertised list, open a URL similar to this")
- +
- (_(" one, but with a '/' and the %(extra)slist name "
- 'appended.<p>'))
- +
- _(" General list information can be found at "),
- Link(Utils.ScriptURL('listinfo'),
- _('the mailing list overview page')),
- "." +
- _("<p>(Send questions and comments to "),
- Link('mailto:%(mailman_owner)s', mailman_owner),
- ".)<p>"
- )
- )
+ extra = msg and _('right ') or ''
+ welcome.extend([
+ _('''To visit the administrators configuration page for an
+ unadvertised list, open a URL similar to this one, but with a '/' and
+ the %(extra)slist name appended.
- table.AddRow([apply(Container, welcome_items)])
+ <p>General list information can be found at '''),
+ Link(Utils.ScriptURL('listinfo'),
+ _('the mailing list overview page')),
+ '.',
+ _('<p>(Send questions and comments to '),
+ Link('mailto:%(mailman_owner)s', mailman_owner),
+ '.)<p>',
+ ])
+
+ table.addRow([Container(*welcome)])
table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2)
if advertised:
table.AddRow(['&nbsp;', '&nbsp;'])
- table.AddRow([Bold(_("List")), Bold(_("Description"))])
- for l in advertised:
+ table.AddRow([Bold(_('List')), Bold(_('Description'))])
+ for mlist in advertised:
table.AddRow(
- [Link(l.GetScriptURL('admin'), Bold(l.real_name)),
- l.description or Italic(_('[no description available]')),
+ [Link(mlist.GetScriptURL('admin'), Bold(mlist.real_name)),
+ mlist.description or Italic(_('[no description available]')),
])
doc.AddItem(table)
@@ -234,24 +248,91 @@ def FormatAdminOverview(error=None):
-def FormatConfiguration(doc, mlist, category, category_suffix, cgi_data):
- """Produce the overall doc, *except* any processing error messages."""
+def option_help(mlist, varhelp):
+ # The html page document
+ doc = Document()
+ doc.set_language(mlist.preferred_language)
+ # Find out which category and variable help is being requested for.
+ item = None
+ reflist = varref.split('/')
+ if len(reflist) == 2:
+ category, varname = reflist
+ options = get_config_options(mlist, category)
+ for i in options:
+ if i and i[0] == varname:
+ item = i
+ break
+ # Print an error message if we couldn't find a valid one
+ if not item:
+ path_info = os.environ.get('PATH_INFO')
+ bad = _('No valid variable details request not found: %(path_info)s')
+ add_error_message(doc, bad)
+ print doc.Format(bgcolor='#fffff')
+ return
+ # Get the details about the variable
+ varname, kind, params, dependancies, description, elaboration = \
+ get_item_characteristics(item)
+ if elaboration is None:
+ elaboration = desc
+ #
+ # Set up the document
+ realname = mlist.real_name
+ legend = _("""%(realname)s Mailing list Configuration Help
+ <br><em>%(varname)s</em> Option""")
+
+ header = Table(width='100%')
+ header.AddRow([Center(Header(3, legend))])
+ header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0,
+ colspan=2, bgcolor="#99ccff")
+ doc.SetTitle(_("Mailman %(varname)s List Option Help"))
+ doc.AddItem(header)
+ doc.AddItem("<b>%s</b> (%s): %s<p>" % (varname, category, descr))
+ doc.AddItem("%s<p>" % elaboration)
+
+ form = Form("%s/%s" % (mlist.GetScriptURL('admin'), category))
+ valtab = Table(cellspacing=3, cellpadding=4)
+ add_options_table_item(mlist, category, valtab, item, detailsp=0)
+ form.AddItem(valtab)
+ form.AddItem('<p>')
+ form.AddItem(Center(submit_button()))
+ doc.AddItem(Center(form))
+
+ doc.AddItem(_("""<em><strong>Warning:</strong> changing this option here
+ could cause other screens to be out-of-sync. Be sure to reload any other
+ pages that are displaying this option for this mailing list. You can also
+ """))
+
+ doc.AddItem(Link('%s/%s' % (mlist.GetScriptURL('admin'), category),
+ _('return to the %(category)s options page.')))
+ doc.AddItem('</em>')
+ doc.AddItem(mlist.GetMailmanFooter())
+ print doc.Format(bgcolor="#ffffff")
+
+
+
+def show_results(mlist, doc, category, category_suffix, cgidata):
+ # Produce the results page
+ global CATEGORIES
+
+ adminurl = mlist.GetScriptURL('admin')
+
for k, v in CATEGORIES:
if k == category:
- label = v
+ label = _(v)
+ break
+ # Set up the document's headers
realname = mlist.real_name
doc.SetTitle(_('%(realname)s Administration (%(label)s)'))
doc.AddItem(Center(Header(2, _(
'%(realname)s mailing list administration<br>%(label)s Section'))))
doc.AddItem('<hr>')
-
- linktable = Table(valign="top")
+ # This holds the two columns of links
+ linktable = Table(valign='top')
linktable.AddRow([Center(Bold(_("Configuration Categories"))),
Center(Bold(_("Other Administrative Activities")))])
- adminurl = mlist.GetScriptURL('admin')
-
+ # The `other links' are stuff in the right column.
otherlinks = UnorderedList()
otherlinks.AddItem(Link(mlist.GetScriptURL('admindb'),
_('Tend to pending administrative requests')))
@@ -259,79 +340,99 @@ def FormatConfiguration(doc, mlist, category, category_suffix, cgi_data):
_('Go to the general list information page')))
otherlinks.AddItem(Link(mlist.GetScriptURL('edithtml'),
_('Edit the HTML for the public list pages')))
- otherlinks.AddItem(Link(mlist.GetBaseArchiveURL(), 'Go to list archives'))
+ otherlinks.AddItem(Link(mlist.GetBaseArchiveURL(),
+ _('Go to list archives')))
otherlinks.AddItem(Link('%s/logout' % adminurl,
- # TBD: What I really want is a blank line :/
- '<FONT SIZE="+2"><b>Logout</b></FONT>'))
-
+ # BAW: What I really want is a blank line, but
+ # adding an &nbsp; won't do it because of the
+ # bullet added to the list item.
+ '<FONT SIZE="+2"><b>%s</b></FONT>' %
+ _('Logout')))
+ # These are links to other categories and live in the left column
categorylinks = UnorderedList()
for k, v in CATEGORIES:
+ url = '%s/%s' % (adminurl, k)
+ # Translate
+ v = _(v)
if k == category:
- categorylinks.AddItem("<em>%s</em>" % v)
- else:
- categorylinks.AddItem(Link("%s/%s" % (adminurl, k), v))
-
+ # 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))
+ # Add all the links to the links table...
linktable.AddRow([categorylinks, otherlinks])
linktable.AddRowInfo(max(linktable.GetCurrentRowIndex(), 0),
- valign="top")
-
+ valign='top')
+ # ...and add the links table to the document.
doc.AddItem(linktable)
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.
if category_suffix:
encoding = None
if category_suffix == 'autoreply':
- # these have file uploads
+ # These have file uploads
encoding = 'multipart/form-data'
form = Form('%s/%s' % (adminurl, category_suffix), encoding=encoding)
else:
form = Form(adminurl)
+ # And add the form
doc.AddItem(form)
-
+ # The general category supports changing the password.
if category == 'general':
- andpassmsg = _(" (You can change your password there, too.)")
+ andpassmsg = _(' (You can change your password there, too.)')
else:
- andpassmsg = ""
- form.AddItem(_("Make your changes below, and then submit them"
- " using the button at the bottom.") +
- andpassmsg + '<p>')
+ andpassmsg = ''
+ form.AddItem(
+ _('''Make your changes below, and then submit them
+ using the button at the bottom.''') +
+ andpassmsg +
+ '<p>')
- form.AddItem(FormatOptionsSection(category, mlist, cgi_data))
+ form.AddItem(show_variables(mlist, category, cgidata))
if category == 'general':
form.AddItem(Center(FormatPasswordStuff()))
form.AddItem("<p>")
- form.AddItem(Center(FormatSubmit()))
+ form.AddItem(Center(submit_button()))
form.AddItem(mlist.GetMailmanFooter())
+ # main() formats and prints the document
-def FormatOptionsSection(category, mlist, cgi_data):
- """Produce the category-specific options table."""
+def show_variables(mlist, category, cgidata):
+ # Produce the category specific variable options table
if category == 'members':
# Special case for members section.
- return FormatMembershipOptions(mlist, cgi_data)
-
- options = GetConfigOptions(mlist, category)
+ return membership_options(mlist, cgidata)
- big_table = Table(cellspacing=3, cellpadding=4)
+ options = get_config_options(mlist, category)
+ # The table containing the results
+ table = Table(cellspacing=3, cellpadding=4)
# Get and portray the text label for the category.
for k, v in CATEGORIES:
if k == category:
- label = v
- big_table.AddRow([Center(Header(2, label))])
- big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0,
+ label = _(v)
+ break
+
+ table.AddRow([Center(Header(2, label))])
+ table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
colspan=2, bgcolor="#99ccff")
- def ColHeader(big_table = big_table):
- big_table.AddRow([Center(Bold(_('Description'))), Center(Bold(_('Value')))])
- big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0,
- width="15%")
- big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 1,
- width="85%")
- did_col_header = 0
+ # Convenience
+ def column_header(table=table):
+ table.AddRow([Center(Bold(_('Description'))),
+ Center(Bold(_('Value')))])
+ table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0,
+ width='15%')
+ table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 1,
+ width='85%')
+ did_col_header = 0
for item in options:
if type(item) == types.StringType:
# The very first banner option (string in an options list) is
@@ -339,35 +440,33 @@ def FormatOptionsSection(category, mlist, cgi_data):
# treated as section headers - centered and italicized...
if did_col_header:
item = "<center><i>" + item + "</i></center>"
- big_table.AddRow([item])
- big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0),
+ table.AddRow([item])
+ table.AddCellInfo(max(table.GetCurrentRowIndex(), 0),
0, colspan=2)
if not did_col_header:
# Do col header after very first string descr, if any...
- ColHeader()
+ column_header()
did_col_header = 1
else:
if not did_col_header:
# ... but do col header before anything else.
- ColHeader()
+ column_header()
did_col_header = 1
- AddOptionsTableItem(big_table, item, category, mlist)
- big_table.AddRow(['<br>'])
- big_table.AddCellInfo(big_table.GetCurrentRowIndex(), 0, colspan=2)
- return big_table
+ add_options_table_item(mlist, category, table, item)
+ table.AddRow(['<br>'])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2)
+ return table
-def AddOptionsTableItem(table, item, category, mlist, detailsp=1):
- """Add a row to an options table with the item description and value."""
- try:
- got = GetItemCharacteristics(item)
- varname, kind, params, dependancies, descr, elaboration = got
- except ValueError, msg:
- syslog('error', 'admin: %s' % msg)
- return Italic(_("<malformed option>"))
- descr = GetItemGuiDescr(mlist, category, varname, descr, detailsp)
- val = GetItemGuiValue(mlist, kind, varname, params)
+def add_options_table_item(mlist, category, table, item, detailsp=1):
+ # Add a row to an options table with the item description and value.
+ varname, kind, params, dependancies, descr, elaboration = \
+ get_item_characteristics(item)
+ if elaboration is None:
+ elaboration = descr
+ descr = get_item_gui_description(mlist, category, varname, descr, detailsp)
+ val = get_item_gui_value(mlist, kind, varname, params)
table.AddRow([descr, val])
table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 1,
bgcolor="#cccccc")
@@ -376,80 +475,28 @@ def AddOptionsTableItem(table, item, category, mlist, detailsp=1):
-def FormatOptionHelp(doc, varref, mlist):
- item = None
- reflist = varref.split('/')
- if len(reflist) == 2:
- category, varname = reflist
- options = GetConfigOptions(mlist, category)
- for i in options:
- if i and i[0] == varname:
- item = i
- break
- if not item:
- bad = _('Option %s/%s not found: %s') % (
- category, varname, os.environ.get('PATH_INFO'))
- AddErrorMessage(doc, bad)
- return
- got = GetItemCharacteristics(item)
- try:
- varname, kind, params, dependancies, descr, elaboration = got
- if elaboration is None:
- elaboration = ''
- except ValueError, msg:
- varname, kind, params, dependancies, descr = got
- elaboration = descr
- header = Table(width="100%")
- realname = mlist.real_name
- legend = (_("""%(realname)s Mailing list Configuration Help
- <br><em>%(varname)s</em> Option"""))
- header.AddRow([Center(Header(3, legend))])
- header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0,
- colspan=2, bgcolor="#99ccff")
- doc.SetTitle(_("Mailman %(varname)s List Option Help"))
- doc.AddItem(header)
- doc.AddItem("<b>%s</b> (%s): %s<p>" % (varname, category, descr))
- doc.AddItem("%s<p>" % elaboration)
-
- form = Form("%s/%s" % (mlist.GetScriptURL('admin'), category))
- valtab = Table(cellspacing=3, cellpadding=4)
- AddOptionsTableItem(valtab, item, category, mlist, detailsp=0)
- form.AddItem(valtab)
- form.AddItem('<p>')
- form.AddItem(Center(FormatSubmit()))
- doc.AddItem(Center(form))
- doc.AddItem(_("""<em><strong>Warning:</strong> changing this option here
- could cause other screens to be out-of-sync. Be sure to reload any other
- pages that are displaying this option for this mailing list. You can
- also """))
- doc.AddItem(Link('%s/%s' % (mlist.GetScriptURL('admin'), category),
- _('return to the %(category)s options page.')))
- doc.AddItem('</em>')
- doc.AddItem(mlist.GetMailmanFooter())
-
-
-
-def GetItemCharacteristics(table_entry):
- """Break out the components of an item description from its table entry:
- 0 option-var name
- 1 type
- 2 entry size
- 3 ?dependancies?
- 4 Brief description
- 5 Optional description elaboration"""
- if len(table_entry) == 5:
+def get_item_characteristics(record):
+ # Break out the components of an item description from its description
+ # record:
+ #
+ # 0 -- option-var name
+ # 1 -- type
+ # 2 -- entry size
+ # 3 -- ?dependancies?
+ # 4 -- Brief description
+ # 5 -- Optional description elaboration
+ if len(record) == 5:
elaboration = None
- varname, kind, params, dependancies, descr = table_entry
- elif len(table_entry) == 6:
- varname, kind, params, dependancies, descr, elaboration = table_entry
+ varname, kind, params, dependancies, descr = record
+ elif len(record) == 6:
+ varname, kind, params, dependancies, descr, elaboration = record
else:
- raise ValueError, (_("Badly formed options entry:\n %s")
- % table_entry)
- return (varname, kind, params, dependancies, descr, elaboration)
+ raise ValueError, _('Badly formed options entry:\n %(record)s')
+ return varname, kind, params, dependancies, descr, elaboration
-def GetItemGuiValue(mlist, kind, varname, params):
+def get_item_gui_value(mlist, kind, varname, params):
"""Return a representation of an item's settings."""
if kind == mm_cfg.Radio or kind == mm_cfg.Toggle:
#
@@ -502,30 +549,28 @@ def GetItemGuiValue(mlist, kind, varname, params):
container.AddItem(_('<br><em>...specify a file to upload</em><br>'))
container.AddItem(FileUpload(varname+'_upload', r, c))
return container
-
- # jcrey - new to deal with language
+ # jcrey - new to deal with language popup
elif kind == mm_cfg.Select:
if params:
values, legend, selected = params
else:
- values = mlist.GetAvailableLanguages()
- legend = map(_, map(Utils.GetLanguageDescr, values))
+ values = mlist.GetAvailableLanguages()
+ legend = map(_, map(Utils.GetLanguageDescr, values))
selected = values.index(mlist.preferred_language)
return SelectOptions(varname, values, legend, selected)
-def GetItemGuiDescr(mlist, category, varname, descr, detailsp):
- """Return the item's description, with link to details.
-
- Details are not included if this is a VARHELP page, because that /is/ the
- details page!
- """
+def get_item_gui_description(mlist, category, varname, descr, detailsp):
+ # Return the item's description, with link to details.
+ #
+ # Details are not included if this is a VARHELP page, because that /is/
+ # the details page!
if detailsp:
text = Container('<div ALIGN="right">' + descr + ' ',
Link(mlist.GetScriptURL('admin')
+ '/?VARHELP=' + category + '/' + varname,
- '(Details)'),
+ _('(Details)')),
'</div>').Format()
else:
text = '<div ALIGN="right">' + descr + '</div>'
@@ -537,7 +582,7 @@ def GetItemGuiDescr(mlist, category, varname, descr, detailsp):
-def FormatMembershipOptions(mlist, cgi_data):
+def membership_options(mlist, cgidata):
container = Container()
header = Table(width="100%")
header.AddRow([Center(Header(2, _("Membership Management")))])
@@ -560,7 +605,8 @@ def FormatMembershipOptions(mlist, cgi_data):
bgcolor="#cccccc", colspan=9)
user_table.AddRow(map(Center, [_('member address'), _('subscr'),
- _('hide'), _('nomail'), _('ack'), _('not metoo'),
+ _('hide'), _('nomail'), _('ack'),
+ _('not metoo'),
_('digest'), _('plain'), _('language')]))
rowindex = user_table.GetCurrentRowIndex()
for i in range(9):
@@ -568,21 +614,23 @@ def FormatMembershipOptions(mlist, cgi_data):
all = mlist.GetMembers() + mlist.GetDigestMembers()
if len(all) > mlist.admin_member_chunksize:
chunks = Utils.chunkify(all, mlist.admin_member_chunksize)
- if not cgi_data.has_key("chunk"):
+ if not cgidata.has_key("chunk"):
chunk = 0
else:
- chunk = int(cgi_data["chunk"].value)
+ chunk = int(cgidata["chunk"].value)
all = chunks[chunk]
- footer = (_("<p><em>To View other sections, "
- "click on the appropriate range listed below</em>"))
+
+ 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=%s/members?chunk=%d>" + _("from %s to %s") + "</a>"
- % (url, ci, start, end))
+ 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>"
else:
@@ -631,22 +679,23 @@ def FormatMembershipOptions(mlist, cgi_data):
container.AddItem(Center(user_table))
legend = UnorderedList()
legend.AddItem(_('<b>subscr</b> -- Is the member subscribed?'))
- legend.AddItem(_("<b>hide</b> -- Is the member's address "
- "concealed on the list of subscribers?"))
+ legend.AddItem(
+ _("""<b>hide</b> -- Is the member's address concealed on
+ the list of subscribers?"""))
legend.AddItem(_('<b>nomail</b> -- Is delivery to the member disabled?'))
- legend.AddItem(_('<b>ack</b> -- '
- 'Does the member get acknowledgements of their posts?'))
- legend.AddItem(_('<b>not metoo</b> -- '
- 'Does the member avoid copies of their own posts?'))
- legend.AddItem(_('<b>digest</b> -- '
- 'Does the member get messages in digests? '
- '(otherwise, individual messages)'))
legend.AddItem(
- _('<b>plain</b> -- '
- 'If getting digests, does the member get plain text digests? '
- '(otherwise, MIME)'))
- legend.AddItem(_("<b>language</b> --"
- "Language preferred by the user"))
+ _('''<b>ack</b> -- Does the member get acknowledgements of their
+ posts?'''))
+ legend.AddItem(
+ _('''<b>not metoo</b> -- Does the member avoid copies of their own
+ posts?'''))
+ legend.AddItem(
+ _('''<b>digest</b> -- Does the member get messages in digests?
+ (otherwise, individual messages)'''))
+ legend.AddItem(
+ _('''<b>plain</b> -- If getting digests, does the member get plain
+ 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%")
@@ -684,7 +733,9 @@ def FormatPasswordStuff():
change_pw_table.AddCellInfo(0, 0, align="left", colspan=2)
old = Table(bgcolor="#99cccc", border=1,
cellspacing=0, cellpadding=2, valign="top")
- old.AddRow(['<div ALIGN="right">' + _(" Enter current password:") + '</div>',
+ old.AddRow(['<div ALIGN="right">' +
+ _(" Enter current password:") +
+ '</div>',
PasswordBox('adminpw')])
new = Table(bgcolor="#99cccc", border=1,
cellspacing=0, cellpadding=2, valign="top")
@@ -699,7 +750,7 @@ def FormatPasswordStuff():
-def FormatSubmit():
+def submit_button():
submit = Table(bgcolor="#99ccff",
border=0, cellspacing=0, cellpadding=2)
submit.AddRow([Bold(SubmitButton('submit', _('Submit Your Changes')))])
@@ -708,11 +759,8 @@ def FormatSubmit():
-# XXX klm - looks like turn_on_moderation is orphaned.
-#turn_on_moderation = 0
-
# Options processing
-def GetValidValue(mlist, prop, my_type, val, dependant):
+def get_valid_value(mlist, prop, my_type, val, dependant):
if my_type == mm_cfg.Radio or my_type == mm_cfg.Toggle:
if type(val) <> types.IntType:
try:
@@ -766,7 +814,7 @@ def GetValidValue(mlist, prop, my_type, val, dependant):
-def ChangeOptions(mlist, category, cgi_info, document):
+def change_options(mlist, category, cgi_info, document):
confirmed = 0
if cgi_info.has_key('newpw'):
if cgi_info.has_key('confirmpw'):
@@ -775,14 +823,14 @@ def ChangeOptions(mlist, category, cgi_info, document):
mlist.ConfirmAdminPassword(cgi_info['adminpw'].value)
confirmed = 1
except Errors.MMBadPasswordError:
- AddErrorMessage(document,
+ add_error_message(document,
_('Incorrect administrator password'),
tag='Error: ')
if confirmed:
new = cgi_info['newpw'].value.strip()
confirm = cgi_info['confirmpw'].value.strip()
if new == '' and confirm == '':
- AddErrorMessage(document,
+ add_error_message(document,
_('Empty admin passwords are not allowed'),
tag='Error: ')
elif new == confirm:
@@ -790,10 +838,10 @@ def ChangeOptions(mlist, category, cgi_info, document):
# Re-authenticate (to set new cookie)
mlist.WebAuthenticate(password=new, cookie='admin')
else:
- AddErrorMessage(document, _('Passwords did not match'),
+ add_error_message(document, _('Passwords did not match'),
tag='Error: ')
else:
- AddErrorMessage(document,
+ add_error_message(document,
_('You must type in your new password twice'),
tag='Error: ')
#
@@ -814,7 +862,7 @@ def ChangeOptions(mlist, category, cgi_info, document):
#
page_setting = int(cgi_info["subscribe_policy"].value)
cgi_info["subscribe_policy"].value = str(page_setting + 1)
- opt_list = GetConfigOptions(mlist, category)
+ opt_list = get_config_options(mlist, category)
for item in opt_list:
if type(item) <> types.TupleType or len(item) < 5:
continue
@@ -826,7 +874,7 @@ def ChangeOptions(mlist, category, cgi_info, document):
continue
else:
val = cgi_info[property].value
- value = GetValidValue(mlist, property, kind, val, deps)
+ value = get_valid_value(mlist, property, kind, val, deps)
#
# This is an ugly, ugly hack
if property[0] == '_':
@@ -849,6 +897,10 @@ def ChangeOptions(mlist, category, cgi_info, document):
changed! It must differ from the list's name by case
only.<p>"""))
continue
+ # Watch for changes to preferred_language. If found, make
+ # sure that the response is generated in the new language.
+ if property == 'preferred_language':
+ i18n.set_language(value)
setattr(mlist, property, value)
#
# mass subscription processing for members category
@@ -936,18 +988,18 @@ def ChangeOptions(mlist, category, cgi_info, document):
mlist.SetUserOption(user, opt_code, 0, save_list=0)
if errors:
document.AddItem(Header(5, _("Error Unsubscribing:")))
- items = map(lambda x: "%s -- %s" % (x[0], x[1]), errors)
+ items = ['%s -- %s' % (x[0], x[1]) for x in errors]
document.AddItem(apply(UnorderedList, tuple((items))))
document.AddItem("<p>")
-def AddErrorMessage(doc, errmsg, tag='Warning: ', *args):
+def add_error_message(doc, errmsg, tag='Warning: ', *args):
doc.AddItem(Header(3, Bold(FontAttr(
_(tag), color="#ff0000", size="+2")).Format() +
Italic(errmsg % args).Format()))
-def GetConfigOptions(mlist, category):
+def get_config_options(mlist, category):
return mlist.GetConfigInfo()[category]