Revision: 8230
          http://svn.sourceforge.net/mailman/?rev=8230&view=rev
Author:   bwarsaw
Date:     2007-05-30 22:01:00 -0700 (Wed, 30 May 2007)

Log Message:
-----------
Add doctest for Replybot handler.  The test in test_handlers.py didn't really
do anything.  The doctest needs to have some way of testing the grace period,
but it's still more tests of the module than there every was before.

Update the Replyboty handler to use $-strings internally.  Eliminate the use
of %-strings in auto-response textsy.  Only $-strings can be used, which
allows us to get rid of another use of SafeDict.

Modified Paths:
--------------
    trunk/mailman/Mailman/Handlers/Replybot.py
    trunk/mailman/Mailman/docs/decorate.txt
    trunk/mailman/Mailman/testing/test_handlers.py

Added Paths:
-----------
    trunk/mailman/Mailman/docs/replybot.txt
    trunk/mailman/Mailman/testing/test_replybot.py

Modified: trunk/mailman/Mailman/Handlers/Replybot.py
===================================================================
--- trunk/mailman/Mailman/Handlers/Replybot.py  2007-05-30 17:14:09 UTC (rev 
8229)
+++ trunk/mailman/Mailman/Handlers/Replybot.py  2007-05-31 05:01:00 UTC (rev 
8230)
@@ -20,14 +20,17 @@
 import time
 import logging
 
+from string import Template
+
 from Mailman import Message
 from Mailman import Utils
 from Mailman.i18n import _
-from Mailman.SafeDict import SafeDict
 
 log = logging.getLogger('mailman.error')
 
+__i18n_templates__ = True
 
+
 
 def process(mlist, msg, msgdata):
     # Normally, the replybot should get a shot at this message, but there are
@@ -69,42 +72,26 @@
             quiet_until = mlist.postings_responses.get(sender, 0)
         if quiet_until > now:
             return
-    #
     # Okay, we know we're going to auto-respond to this sender, craft the
     # message, send it, and update the database.
     realname = mlist.real_name
     subject = _(
-        'Auto-response for your message to the "%(realname)s" mailing list')
-    # Do string interpolation
-    d = SafeDict({'listname'    : realname,
-                  'listurl'     : mlist.GetScriptURL('listinfo'),
-                  'requestemail': mlist.GetRequestEmail(),
-                  # BAW: Deprecate adminemail; it's not advertised but still
-                  # supported for backwards compatibility.
-                  'adminemail'  : mlist.GetBouncesEmail(),
-                  'owneremail'  : mlist.GetOwnerEmail(),
-                  })
-    # Just because we're using a SafeDict doesn't mean we can't get all sorts
-    # of other exceptions from the string interpolation.  Let's be ultra
-    # conservative here.
+        'Auto-response for your message to the "$realname" mailing list')
+    # Do string interpolation into the autoresponse text
+    d = dict(listname       = realname,
+             listurl        = mlist.GetScriptURL('listinfo'),
+             requestemail   = mlist.request_address,
+             owneremail     = mlist.owner_address,
+             )
     if toadmin:
         rtext = mlist.autoresponse_admin_text
     elif torequest:
         rtext = mlist.autoresponse_request_text
     else:
         rtext = mlist.autoresponse_postings_text
-    # Using $-strings?
-    if getattr(mlist, 'use_dollar_strings', 0):
-        rtext = Utils.to_percent(rtext)
-    try:
-        text = rtext % d
-    except Exception:
-        log.error('Bad autoreply text for list: %s\n%s',
-                  mlist.internal_name(), rtext)
-        text = rtext
-    # Wrap the response.
-    text = Utils.wrap(text)
-    outmsg = Message.UserNotification(sender, mlist.GetBouncesEmail(),
+    # Interpolation and Wrap the response text.
+    text = Utils.wrap(Template(rtext).safe_substitute(d))
+    outmsg = Message.UserNotification(sender, mlist.bounces_address,
                                       subject, text, mlist.preferred_language)
     outmsg['X-Mailer'] = _('The Mailman Replybot')
     # prevent recursions and mail loops!

Modified: trunk/mailman/Mailman/docs/decorate.txt
===================================================================
--- trunk/mailman/Mailman/docs/decorate.txt     2007-05-30 17:14:09 UTC (rev 
8229)
+++ trunk/mailman/Mailman/docs/decorate.txt     2007-05-31 05:01:00 UTC (rev 
8230)
@@ -10,6 +10,7 @@
     >>> from Mailman.configuration import config
     >>> from Mailman.database import flush
     >>> mlist = config.list_manager.create('[EMAIL PROTECTED]')
+    >>> flush()
     >>> msg_text = """\
     ... From: [EMAIL PROTECTED]
     ...
@@ -66,9 +67,6 @@
 data.  An example of such information is the mailing list's "real name" (a
 short descriptive name for the mailing list).
 
-    # XXX Remove this line after converting this test
-    >>> mlist.use_dollar_strings = True
-
     >>> msg = message_from_string(msg_text)
     >>> mlist.msg_header = '$real_name header\n'
     >>> mlist.msg_footer = '$real_name footer'

Added: trunk/mailman/Mailman/docs/replybot.txt
===================================================================
--- trunk/mailman/Mailman/docs/replybot.txt                             (rev 0)
+++ trunk/mailman/Mailman/docs/replybot.txt     2007-05-31 05:01:00 UTC (rev 
8230)
@@ -0,0 +1,230 @@
+Auto-reply handler
+==================
+
+Mailman has an auto-reply handler that sends automatic responses to messages
+it receives on its posting address, or special robot addresses.  Automatic
+responses are subject to various conditions, such as headers in the original
+message or the amount of time since the last auto-response.
+
+    >>> from email import message_from_string
+    >>> from Mailman.Handlers.Replybot import process
+    >>> from Mailman.Message import Message
+    >>> from Mailman.configuration import config
+    >>> from Mailman.database import flush
+    >>> mlist = config.list_manager.create('[EMAIL PROTECTED]')
+    >>> mlist.real_name = 'XTest'
+    >>> flush()
+
+    >>> # Ensure that the virgin queue is empty, since we'll be checking this
+    >>> # for new auto-response messages.
+    >>> from Mailman.Queue.sbcache import get_switchboard
+    >>> virginq = get_switchboard(config.VIRGINQUEUE_DIR)
+    >>> virginq.files()
+    []
+
+
+Basic autoresponding
+--------------------
+
+Basic autoresponding occurs when the list is set up to respond to either its
+-owner address, its -request address, or to the posting address, and a message
+is sent to one of these addresses.  A mailing list also has an autoresponse
+grace period which describes how much time must pass before a second response
+will be sent, with 0 meaning "there is no grace period".
+
+    >>> mlist.autorespond_admin = True
+    >>> mlist.autoresponse_graceperiod = 0
+    >>> mlist.autoresponse_admin_text = 'admin autoresponse text'
+    >>> flush()
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ... To: [EMAIL PROTECTED]
+    ...
+    ... help
+    ... """, Message)
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> len(virginq.files())
+    1
+    >>> qmsg, qdata = virginq.dequeue(virginq.files()[0])
+    >>> # Print only some of the meta data.  The rest is uninteresting.
+    >>> qdata['listname']
+    '[EMAIL PROTECTED]'
+    >>> sorted(qdata['recips'])
+    ['[EMAIL PROTECTED]']
+    >>> # Delete data that is time dependent or random
+    >>> del qmsg['message-id']
+    >>> del qmsg['date']
+    >>> print qmsg.as_string()
+    MIME-Version: 1.0
+    Content-Type: text/plain; charset="us-ascii"
+    Content-Transfer-Encoding: 7bit
+    Subject: Auto-response for your message to the "XTest" mailing list
+    From: [EMAIL PROTECTED]
+    To: [EMAIL PROTECTED]
+    X-Mailer: The Mailman Replybot
+    X-Ack: No
+    Precedence: bulk
+    <BLANKLINE>
+    admin autoresponse text
+    >>> virginq.files()
+    []
+
+
+Short circuiting
+----------------
+
+Several headers in the original message determine whether an autoresponse
+should even be sent.  For example, if the message has an "X-Ack: No" header,
+no auto-response is sent.
+
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ... X-Ack: No
+    ...
+    ... help me
+    ... """, Message)
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> virginq.files()
+    []
+
+Mailman itself can suppress autoresponses for certain types of internally
+crafted messages, by setting the 'noack' metadata key.
+
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ...
+    ... help for you
+    ... """, Message)
+    >>> process(mlist, msg, dict(noack=True, toowner=True))
+    >>> virginq.files()
+    []
+
+If there is a Precedence: header with any of the values 'bulk', 'junk', or
+'list', then the autoresponse is also suppressed.
+
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ... Precedence: bulk
+    ...
+    ... hey!
+    ... """, Message)
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> virginq.files()
+    []
+
+    >>> msg.replace_header('precedence', 'junk')
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> virginq.files()
+    []
+    >>> msg.replace_header('precedence', 'list')
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> virginq.files()
+    []
+
+Unless the X-Ack: header has a value of "yes", in which case, the Precedence
+header is ignored.
+
+    >>> msg['X-Ack'] = 'yes'
+    >>> process(mlist, msg, dict(toowner=True))
+    >>> len(virginq.files())
+    1
+    >>> qmsg, qdata = virginq.dequeue(virginq.files()[0])
+    >>> del qmsg['message-id']
+    >>> del qmsg['date']
+    >>> print qmsg.as_string()
+    MIME-Version: 1.0
+    Content-Type: text/plain; charset="us-ascii"
+    Content-Transfer-Encoding: 7bit
+    Subject: Auto-response for your message to the "XTest" mailing list
+    From: [EMAIL PROTECTED]
+    To: [EMAIL PROTECTED]
+    X-Mailer: The Mailman Replybot
+    X-Ack: No
+    Precedence: bulk
+    <BLANKLINE>
+    admin autoresponse text
+
+
+Available auto-responses
+------------------------
+
+As shown above, a message sent to the -owner address will get an auto-response
+with the text set for owner responses.  Two other types of email will get
+auto-responses: those sent to the -request address...
+
+    >>> mlist.autorespond_requests = True
+    >>> mlist.autoresponse_request_text = 'robot autoresponse text'
+    >>> flush()
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ... To: [EMAIL PROTECTED]
+    ...
+    ... help me
+    ... """, Message)
+    >>> process(mlist, msg, dict(torequest=True))
+    >>> len(virginq.files())
+    1
+    >>> qmsg, qdata = virginq.dequeue(virginq.files()[0])
+    >>> del qmsg['message-id']
+    >>> del qmsg['date']
+    >>> print qmsg.as_string()
+    MIME-Version: 1.0
+    Content-Type: text/plain; charset="us-ascii"
+    Content-Transfer-Encoding: 7bit
+    Subject: Auto-response for your message to the "XTest" mailing list
+    From: [EMAIL PROTECTED]
+    To: [EMAIL PROTECTED]
+    X-Mailer: The Mailman Replybot
+    X-Ack: No
+    Precedence: bulk
+    <BLANKLINE>
+    robot autoresponse text
+
+...and those sent to the posting address.
+
+    >>> mlist.autorespond_postings = True
+    >>> mlist.autoresponse_postings_text = 'postings autoresponse text'
+    >>> flush()
+    >>> msg = message_from_string("""\
+    ... From: [EMAIL PROTECTED]
+    ... To: [EMAIL PROTECTED]
+    ...
+    ... help me
+    ... """, Message)
+    >>> process(mlist, msg, {})
+    >>> len(virginq.files())
+    1
+    >>> qmsg, qdata = virginq.dequeue(virginq.files()[0])
+    >>> del qmsg['message-id']
+    >>> del qmsg['date']
+    >>> print qmsg.as_string()
+    MIME-Version: 1.0
+    Content-Type: text/plain; charset="us-ascii"
+    Content-Transfer-Encoding: 7bit
+    Subject: Auto-response for your message to the "XTest" mailing list
+    From: [EMAIL PROTECTED]
+    To: [EMAIL PROTECTED]
+    X-Mailer: The Mailman Replybot
+    X-Ack: No
+    Precedence: bulk
+    <BLANKLINE>
+    postings autoresponse text
+
+
+Grace periods
+-------------
+
+Auto-responses have a grace period, during which no additional responses will
+be sent.  This is so as not to bombard the sender with responses.  The grace
+period is measured in days.
+
+XXX Add grace period tests.
+
+
+Clean up
+--------
+
+    >>> config.list_manager.delete(mlist)
+    >>> flush()
+    >>> [name for name in config.list_manager.names]
+    []

Modified: trunk/mailman/Mailman/testing/test_handlers.py
===================================================================
--- trunk/mailman/Mailman/testing/test_handlers.py      2007-05-30 17:14:09 UTC 
(rev 8229)
+++ trunk/mailman/Mailman/testing/test_handlers.py      2007-05-31 05:01:00 UTC 
(rev 8230)
@@ -46,7 +46,6 @@
 from Mailman.Handlers import Hold
 from Mailman.Handlers import MimeDel
 from Mailman.Handlers import Moderate
-from Mailman.Handlers import Replybot
 from Mailman.Handlers import Scrubber
 # Don't test handlers such as SMTPDirect and Sendmail here
 from Mailman.Handlers import SpamDetect
@@ -1205,11 +1204,6 @@
 
 
 
-class TestReplybot(TestBase):
-    pass
-
-
-
 class TestScrubber(TestBase):
     def test_save_attachment(self):
         mlist = self._mlist
@@ -1716,7 +1710,6 @@
     suite.addTest(unittest.makeSuite(TestHold))
     suite.addTest(unittest.makeSuite(TestMimeDel))
     suite.addTest(unittest.makeSuite(TestModerate))
-    suite.addTest(unittest.makeSuite(TestReplybot))
     suite.addTest(unittest.makeSuite(TestScrubber))
     suite.addTest(unittest.makeSuite(TestSpamDetect))
     suite.addTest(unittest.makeSuite(TestTagger))

Added: trunk/mailman/Mailman/testing/test_replybot.py
===================================================================
--- trunk/mailman/Mailman/testing/test_replybot.py                              
(rev 0)
+++ trunk/mailman/Mailman/testing/test_replybot.py      2007-05-31 05:01:00 UTC 
(rev 8230)
@@ -0,0 +1,32 @@
+# Copyright (C) 2007 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.
+
+"""Doctest harness for testing the replybot handler."""
+
+import doctest
+import unittest
+
+options = (doctest.ELLIPSIS
+           | doctest.NORMALIZE_WHITESPACE
+           | doctest.REPORT_NDIFF)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocFileSuite('../docs/replybot.txt',
+                                       optionflags=options))
+    return suite


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.
_______________________________________________
Mailman-checkins mailing list
[email protected]
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to