changeset 1320:3758a5af985f

Lots of little fixes in this update: - fixed Date.local() - email quoted text stripping is controllable again [SF#650742] - extract attachment name from content-disposition if name missing [SF#637278] - removed FILTER_POSITION from bundled configs - reverse message listing in issue display (reversion of recent change) - bad entries for multilink editing in cgi don't traceback now [SF#640310]
author Richard Jones <richard@users.sourceforge.net>
date Tue, 10 Dec 2002 00:11:16 +0000
parents f8cc0b724b28
children 328d68db2ef8
files CHANGES.txt TODO.txt doc/customizing.txt roundup/__init__.py roundup/cgi/client.py roundup/cgi/templating.py roundup/mailgw.py roundup/templates/classic/config.py roundup/templates/classic/html/issue.item roundup/templates/minimal/config.py setup.py test/test_mailgw.py
diffstat 12 files changed, 128 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Mon Dec 09 02:51:46 2002 +0000
+++ b/CHANGES.txt	Tue Dec 10 00:11:16 2002 +0000
@@ -9,6 +9,13 @@
 - removed use of string/strop from TAL/TALInterpreter
 - handle KeyboardInterrupt nicely
 - fixed Date and Interval form value handling
+- fixed Date.local()
+- email quoted text stripping is controllable again (sf bug 650742)
+- extract attachment name from content-disposition if name is missing (sf
+  bug 637278)
+- removed FILTER_POSITION from bundled configs
+- reverse message listing in issue display (reversion of recent change)
+- bad entries for multilink editing in cgi don't traceback now (sf bug 640310)
 
 
 2002-11-07 0.5.2
--- a/TODO.txt	Mon Dec 09 02:51:46 2002 +0000
+++ b/TODO.txt	Tue Dec 10 00:11:16 2002 +0000
@@ -16,6 +16,8 @@
                   [value, value, ...] implies "in"
 pending hyperdb   migrate "id" property to be Number type
 pending hyperdb   multilink sorting by length is dumb
+pending hyperdb   lastchangedby auto-property giving last user to change an
+                  item
 pending tracker   split instance.open() into open() and login()
 pending mailgw    allow commands (feature request #556996)
                   like "help", "dump issue123" (would send all info about
@@ -33,6 +35,8 @@
                   strictness (ie. turn off username==address matching)
 pending mailgw    Use in-reply-to for determining message lineage when subject
                   line lets us down
+pending mailgw    Allow different brackets delimiting [issueNNN] in Subject
+pending email     email sig could use a "remove me from this list"
 pending messages  Snarf the first whole sentence, or full first line of
                   messages for the summary - whichever is longer.
 pending project   switch to a Roundup instance for Roundup bug/feature tracking
@@ -56,14 +60,18 @@
 pending web       automagically link designators
 pending web       add checkbox-based removal/addition for multilink entries
                   (eg "add me"/"remove me" for nosy list)
-pending web       multilink item removal action (with retirement)
 pending web       search "refinement" - pre-fill the search page with the
                   current search parameters
 pending web       column-heading sort stuff isn't implemented
+pending web       multilink item removal action with retirement
+pending web       implement a python dict version of the form values
 
 active  web       UNIX init.d script for roundup-server
 bug     web       query editing isn't fully implemented
 bug     web       no testing for parsePropsFromForm
 active  web       revert to showing entire message in classic issue display
+bug     hyperdb   pysqlite and locks
+                  http://www.hwaci.com/sw/sqlite/c_interface.html
+bug     web       implement the request.url attribute?
 ======= ========= =============================================================
 
--- a/doc/customizing.txt	Mon Dec 09 02:51:46 2002 +0000
+++ b/doc/customizing.txt	Tue Dec 10 00:11:16 2002 +0000
@@ -2,7 +2,7 @@
 Customising Roundup
 ===================
 
-:Version: $Revision: 1.63 $
+:Version: $Revision: 1.64 $
 
 .. This document borrows from the ZopeBook section on ZPT. The original is at:
    http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -1486,6 +1486,10 @@
 Searching Views
 ---------------
 
+Note: if you add a new column to the ``:columns`` form variable potentials
+      then you will need to add the column to the `index view`_
+      template so it is actually displayed.
+
 This is one of the class context views. The template used is typically
 "*classname*.search". The form on this page should have "search" as its
 ``:action`` variable. The "search" action:
@@ -1515,7 +1519,6 @@
   template schema does not.
 
 
-
 Item Views
 ----------
 
--- a/roundup/__init__.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/__init__.py	Tue Dec 10 00:11:16 2002 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: __init__.py,v 1.16 2002-11-06 11:38:42 richard Exp $
+# $Id: __init__.py,v 1.17 2002-12-10 00:11:14 richard Exp $
 
 ''' Roundup - issue tracking for knowledge workers.
 
@@ -67,6 +67,6 @@
 much prettier cake :)
 '''
 
-__version__ = '0.5.2'
+__version__ = '0.5.3'
 
 # vim: set filetype=python ts=4 sw=4 et si
--- a/roundup/cgi/client.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/cgi/client.py	Tue Dec 10 00:11:16 2002 +0000
@@ -1,4 +1,4 @@
-# $Id: client.py,v 1.58 2002-11-28 07:08:39 richard Exp $
+# $Id: client.py,v 1.59 2002-12-10 00:11:15 richard Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -691,7 +691,7 @@
             props = self._changenode(props)
             # handle linked nodes 
             self._post_editnode(self.nodeid)
-        except (ValueError, KeyError), message:
+        except (ValueError, KeyError, IndexError), message:
             self.error_message.append(_('Error: ') + str(message))
             return
 
@@ -771,7 +771,19 @@
         try:
             # do the create
             nid = self._createnode(props)
+        except (ValueError, KeyError, IndexError), message:
+            # these errors might just be indicative of user dumbness
+            self.error_message.append(_('Error: ') + str(message))
+            return
+        except:
+            # oops
+            self.db.rollback()
+            s = StringIO.StringIO()
+            traceback.print_exc(None, s)
+            self.error_message.append('<pre>%s</pre>'%cgi.escape(s.getvalue()))
+            return
 
+        try:
             # handle linked nodes 
             self._post_editnode(nid)
 
@@ -783,9 +795,6 @@
 
             # and some nice feedback for the user
             message = _('%(classname)s created ok')%self.__dict__ + xtra
-        except (ValueError, KeyError), message:
-            self.error_message.append(_('Error: ') + str(message))
-            return
         except:
             # oops
             self.db.rollback()
--- a/roundup/cgi/templating.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/cgi/templating.py	Tue Dec 10 00:11:16 2002 +0000
@@ -891,6 +891,12 @@
         '''
         return self._value.pretty()
 
+    def local(self, offset):
+        ''' Return the date/time as a local (timezone offset) date/time.
+        '''
+        return DateHTMLProperty(self._client, self._nodeid, self._prop,
+            self._name, self._value.local())
+
 class IntervalHTMLProperty(HTMLProperty):
     def plain(self):
         ''' Render a "plain" representation of the property
@@ -965,6 +971,7 @@
         else:
             s = ''
         l.append(_('<option %svalue="-1">- no selection -</option>')%s)
+        # XXX if the current value is retired, then list it explicitly
         for optionid in options:
             # get the option value, and if it's None use an empty string
             option = linkcl.get(optionid, k) or ''
@@ -1011,6 +1018,7 @@
         else:  
             sort_on = ('+', linkcl.labelprop())
         options = linkcl.filter(None, conditions, sort_on, (None, None))
+        # XXX if the current value is retired, then list it explicitly
         for optionid in options:
             # get the option value, and if it's None use an empty string
             option = linkcl.get(optionid, k) or ''
@@ -1131,6 +1139,7 @@
         height = height or min(len(options), 7)
         l = ['<select multiple name="%s" size="%s">'%(self._name, height)]
         k = linkcl.labelprop(1)
+        # XXX if any of the current values are retired, then list them
         for optionid in options:
             # get the option value, and if it's None use an empty string
             option = linkcl.get(optionid, k) or ''
--- a/roundup/mailgw.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/mailgw.py	Tue Dec 10 00:11:16 2002 +0000
@@ -73,7 +73,7 @@
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.99 2002-11-05 22:59:46 richard Exp $
+$Id: mailgw.py,v 1.100 2002-12-10 00:11:15 richard Exp $
 '''
 
 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
@@ -723,7 +723,11 @@
                     attachments.append((name, 'message/rfc822', part.fp.read()))
                 else:
                     # try name on Content-Type
-                    name = part.getparam('name')
+                    name = part.getparam('name').strip()
+                    if not name:
+                        disp = part.getheader('content-disposition', None)
+                        if disp:
+                            name = disp.getparam('filename').strip()
                     # this is just an attachment
                     data = self.get_part_data_decoded(part) 
                     attachments.append((name, part.gettype(), data))
@@ -761,9 +765,9 @@
             content = self.get_part_data_decoded(message) 
  
         # figure how much we should muck around with the email body
-        keep_citations = getattr(self.instance, 'EMAIL_KEEP_QUOTED_TEXT',
+        keep_citations = getattr(self.instance.config, 'EMAIL_KEEP_QUOTED_TEXT',
             'no') == 'yes'
-        keep_body = getattr(self.instance, 'EMAIL_LEAVE_BODY_UNCHANGED',
+        keep_body = getattr(self.instance.config, 'EMAIL_LEAVE_BODY_UNCHANGED',
             'no') == 'yes'
 
         # parse the body of the message, stripping out bits as appropriate
--- a/roundup/templates/classic/config.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/templates/classic/config.py	Tue Dec 10 00:11:16 2002 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: config.py,v 1.4 2002-11-07 21:17:44 richard Exp $
+# $Id: config.py,v 1.5 2002-12-10 00:11:16 richard Exp $
 
 import os
 
@@ -47,9 +47,6 @@
 # The email address that roundup will complain to if it runs into trouble
 ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
 
-# Where to place the web filtering HTML on the index page
-FILTER_POSITION = 'bottom'          # one of 'top', 'bottom', 'top and bottom'
-
 # 
 # SECURITY DEFINITIONS
 #
--- a/roundup/templates/classic/html/issue.item	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/templates/classic/html/issue.item	Tue Dec 10 00:11:16 2002 +0000
@@ -128,7 +128,7 @@
 
  <table class="messages" tal:condition="context/messages">
   <tr><th colspan="4" class="header">Messages</th></tr>
-  <tal:block tal:repeat="msg context/messages">
+  <tal:block tal:repeat="msg context/messages/reverse">
    <tr>
     <th><a tal:attributes="href string:msg${msg/id}"
            tal:content="string:msg${msg/id}"></a></th>
--- a/roundup/templates/minimal/config.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/roundup/templates/minimal/config.py	Tue Dec 10 00:11:16 2002 +0000
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: config.py,v 1.2 2002-11-07 21:17:44 richard Exp $
+# $Id: config.py,v 1.3 2002-12-10 00:11:16 richard Exp $
 
 import os
 
@@ -47,9 +47,6 @@
 # The email address that roundup will complain to if it runs into trouble
 ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
 
-# Where to place the web filtering HTML on the index page
-FILTER_POSITION = 'bottom'          # one of 'top', 'bottom', 'top and bottom'
-
 # 
 # SECURITY DEFINITIONS
 #
--- a/setup.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/setup.py	Tue Dec 10 00:11:16 2002 +0000
@@ -16,7 +16,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: setup.py,v 1.40 2002-10-17 00:22:16 richard Exp $
+# $Id: setup.py,v 1.41 2002-12-10 00:11:13 richard Exp $
 
 from distutils.core import setup, Extension
 from distutils.util import get_platform
@@ -25,6 +25,11 @@
 import sys, os, string
 from glob import glob
 
+# patch distutils if it can't cope with the "classifiers" keyword
+if sys.version < '2.2.3':
+    from distutils.dist import DistributionMetadata
+    DistributionMetadata.classifiers = None
+
 from roundup.templates.builder import makeHtmlBase
 
 
@@ -180,6 +185,22 @@
         author_email = "richard@users.sourceforge.net",
         url = 'http://sourceforge.net/projects/roundup/',
         packages = packagelist,
+        classifiers = [
+            'Development Status :: 4 - Beta',
+            'Environment :: Console',
+            'Environment :: Web Environment',
+            'Intended Audience :: End Users/Desktop',
+            'Intended Audience :: Developers',
+            'Intended Audience :: System Administrators',
+            'License :: OSI Approved :: Python Software Foundation License',
+            'Operating System :: MacOS :: MacOS X',
+            'Operating System :: Microsoft :: Windows',
+            'Operating System :: POSIX',
+            'Programming Language :: Python',
+            'Topic :: Communications :: Email',
+            'Topic :: Office/Business',
+            'Topic :: Software Development :: Bug Tracking',
+        ],
 
         # Override certain command classes with our own ones
         cmdclass = {
--- a/test/test_mailgw.py	Mon Dec 09 02:51:46 2002 +0000
+++ b/test/test_mailgw.py	Tue Dec 10 00:11:16 2002 +0000
@@ -8,7 +8,7 @@
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 #
-# $Id: test_mailgw.py,v 1.33 2002-11-05 22:59:46 richard Exp $
+# $Id: test_mailgw.py,v 1.34 2002-12-10 00:11:16 richard Exp $
 
 import unittest, cStringIO, tempfile, os, shutil, errno, imp, sys, difflib
 
@@ -119,6 +119,7 @@
         l = self.db.issue.get(nodeid, 'nosy')
         l.sort()
         self.assertEqual(l, ['3', '4'])
+        return nodeid
 
     def testNewIssue(self):
         self.doNewIssue()
@@ -819,6 +820,53 @@
 _______________________________________________________________________
 ''')
 
+    def testEmailQuoting(self):
+        self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
+        self.innerTestQuoting('''This is a followup
+''')
+
+    def testEmailQuotingRemove(self):
+        self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
+        self.innerTestQuoting('''Blah blah wrote:
+> Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
+>  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
+>
+
+This is a followup
+''')
+
+    def innerTestQuoting(self, expect):
+        nodeid = self.doNewIssue()
+
+        messages = self.db.issue.get(nodeid, 'messages')
+
+        message = cStringIO.StringIO('''Content-Type: text/plain;
+  charset="iso-8859-1"
+From: richard <richard@test>
+To: issue_tracker@your.tracker.email.domain.example
+Message-Id: <followup_dummy_id>
+In-Reply-To: <dummy_test_message_id>
+Subject: Re: [issue1] Testing...
+
+Blah blah wrote:
+> Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
+>  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
+>
+
+This is a followup
+''')
+        handler = self.instance.MailGW(self.instance, self.db)
+        handler.trapExceptions = 0
+        handler.main(message)
+
+        # figure the new message id
+        newmessages = self.db.issue.get(nodeid, 'messages')
+        for msg in messages:
+            newmessages.remove(msg)
+        messageid = newmessages[0]
+
+        self.compareStrings(self.db.msg.get(messageid, 'content'), expect)
+
 def suite():
     l = [unittest.makeSuite(MailgwTestCase),
     ]

Roundup Issue Tracker: http://roundup-tracker.org/