Mercurial > p > roundup > code
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), ]
