summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: dc49cf9)
raw | patch | inline | side by side (parent: dc49cf9)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 9 May 2003 01:47:51 +0000 (01:47 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 9 May 2003 01:47:51 +0000 (01:47 +0000) |
- multilink properties may hhave multiple form values "1", "2,4", "5", ...
- string search properties are split on whitespace and match any of the
values
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1697 57a73879-2fb5-44c3-a270-3262357dd7e2
- string search properties are split on whitespace and match any of the
values
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1697 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index cb161461277ecf1f6aa1d722f82f626a9f4dc329..fb7e8fcda7e76361f78acb887ea6de0dafec34dd 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
3rd-party templates.
- extended date syntax to make range searches even more useful
- SMTP login and TLS support added (sf bug 710853 with extras ;)
+ Note: requires python 2.2+
Fixed:
- applied unicode patch. All data is stored in utf-8. Incoming messages
(sf "bug" 621226 for the users of the "standards compliant" browser IE)
-2003-??-?? 0.5.7
+2003-05-08 0.5.7
- fixed Interval maths (sf bug 665357)
- fixed sqlite rollback/caching bug (sf bug 689383)
- fixed rdbms table update detection logic (sf bug 703297)
index 8299415e12658d3cb1b88178b958bbfc710b443a..b15ce46f78b2a55be665b13f7dc1416c7e7cd2f6 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.120 2003-04-22 20:53:54 kedder Exp $
+#$Id: back_anydbm.py,v 1.121 2003-05-09 01:47:50 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
u.sort()
l.append((MULTILINK, k, u))
elif isinstance(propclass, String) and k != 'id':
- # simple glob searching
- v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
- v = v.replace('?', '.')
- v = v.replace('*', '.*?')
- l.append((STRING, k, re.compile(v, re.I)))
+ if type(v) is not type([]):
+ v = [v]
+ m = []
+ for v in v:
+ # simple glob searching
+ v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
+ v = v.replace('?', '.')
+ v = v.replace('*', '.*?')
+ m.append(v)
+ m = re.compile('(%s)'%('|'.join(m)), re.I)
+ l.append((STRING, k, m))
elif isinstance(propclass, Date):
try:
date_rng = Range(v, date.Date, offset=timezone)
continue
break
elif t == STRING:
+ if node[k] is None:
+ break
# RE search
- if node[k] is None or not v.search(node[k]):
+ if not v.search(node[k]):
break
elif t == DATE or t == INTERVAL:
- if node[k] is None: break
+ if node[k] is None:
+ break
if v.to_value:
if not (v.from_value <= node[k] and v.to_value >= node[k]):
break
index b4ce8688ca5ece62f1e68131c3a7fe0005d01633..bffebf9116d20d6b3ec0b30e3c2626b9cd6d29fa 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_bsddb.py,v 1.25 2003-03-26 11:19:28 richard Exp $
+#$Id: back_bsddb.py,v 1.26 2003-05-09 01:47:50 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in BSDDB.
'''
#
def getjournal(self, classname, nodeid):
''' get the journal for id
+
+ Raise IndexError if the node doesn't exist (as per history()'s
+ API)
'''
if __debug__:
print >>hyperdb.DEBUG, 'getjournal', (self, classname, nodeid)
db.close()
# add all the saved journal entries for this node
- for entry in journal:
- (nodeid, date_stamp, user, action, params) = entry
- date_obj = date.Date(date_stamp)
- res.append((nodeid, date_obj, user, action, params))
+ for nodeid, date_stamp, user, action, params in journal:
+ res.append((nodeid, date.Date(date_stamp), user, action, params))
return res
def getCachedJournalDB(self, classname):
index f894047ea6c2ea9710e19a6d1711495e33f4c6c1..90f337903254a46cbfe4d4126bfbab3b31abe2e5 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_bsddb3.py,v 1.18 2002-10-03 06:56:29 richard Exp $
+#$Id: back_bsddb3.py,v 1.19 2003-05-09 01:47:50 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in BSDDB3.
'''
#
def getjournal(self, classname, nodeid):
''' get the journal for id
+
+ Raise IndexError if the node doesn't exist (as per history()'s
+ API)
'''
+ if __debug__:
+ print >>hyperdb.DEBUG, 'getjournal', (self, classname, nodeid)
+
+ # our journal result
+ res = []
+
+ # add any journal entries for transactions not committed to the
+ # database
+ for method, args in self.transactions:
+ if method != self.doSaveJournal:
+ continue
+ (cache_classname, cache_nodeid, cache_action, cache_params,
+ cache_creator, cache_creation) = args
+ if cache_classname == classname and cache_nodeid == nodeid:
+ if not cache_creator:
+ cache_creator = self.curuserid
+ if not cache_creation:
+ cache_creation = date.Date()
+ res.append((cache_nodeid, cache_creation, cache_creator,
+ cache_action, cache_params))
+
# attempt to open the journal - in some rare cases, the journal may
# not exist
try:
raise IndexError, 'no such %s %s'%(classname, nodeid)
# more handling of bad journals
if not db.has_key(nodeid):
+ db.close()
+ if res:
+ # we have some unsaved journal entries, be happy!
+ return res
raise IndexError, 'no such %s %s'%(classname, nodeid)
journal = marshal.loads(db[nodeid])
- res = []
- for entry in journal:
- (nodeid, date_stamp, user, action, params) = entry
- date_obj = date.Date(date_stamp)
- res.append((nodeid, date_obj, user, action, params))
db.close()
+
+ # add all the saved journal entries for this node
+ for nodeid, date_stamp, user, action, params in journal:
+ res.append((nodeid, date.Date(date_stamp), user, action, params))
return res
def getCachedJournalDB(self, classname):
index 7b94ac847e8b384601485db7e672e448f7f448ea..34828679aaa7a389b68305a2dc2a36f06e039a3e 100755 (executable)
-# $Id: back_metakit.py,v 1.46 2003-04-20 11:58:45 kedder Exp $
+# $Id: back_metakit.py,v 1.47 2003-05-09 01:47:50 richard Exp $
'''
Metakit backend for Roundup, originally by Gordon McMillan.
else:
orcriteria[propname] = u
elif isinstance(prop, hyperdb.String):
- # simple glob searching
- v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', value)
- v = v.replace('?', '.')
- v = v.replace('*', '.*?')
- regexes[propname] = re.compile(v, re.I)
+ if type(value) is not type([]):
+ value = [value]
+ m = []
+ for v in value:
+ # simple glob searching
+ v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
+ v = v.replace('?', '.')
+ v = v.replace('*', '.*?')
+ m.append(v)
+ regexes[propname] = re.compile('(%s)'%('|'.join(m)), re.I)
elif propname == 'id':
where[propname] = int(value)
elif isinstance(prop, hyperdb.Boolean):
diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py
index 007d7a04315d9eb40ad2b6cbeae9787309b912e3..97df1733b750fdfca9aa726b56ea4f137002d686 100644 (file)
--- a/roundup/cgi/client.py
+++ b/roundup/cgi/client.py
-# $Id: client.py,v 1.114 2003-04-24 07:19:59 richard Exp $
+# $Id: client.py,v 1.115 2003-05-09 01:47:50 richard Exp $
__doc__ = """
WWW request handler (also used in the stand-alone server).
return 0
return 1
- def searchAction(self):
+ def searchAction(self, wcre=re.compile(r'[\s,]+')):
''' Mangle some of the form variables.
Set the form ":filter" variable based on the values of the
filter variables - if they're set to anything other than
"dontcare" then add them to :filter.
- Also handle the ":queryname" variable and save off the query to
+ Handle the ":queryname" variable and save off the query to
the user's query list.
+
+ Split any String query values on whitespace and comma.
'''
# generic edit is per-class only
if not self.searchPermission():
else:
if not self.form[key].value:
continue
+ if isinstance(props[key], hyperdb.String):
+ v = self.form[key].value
+ l = wcre.split(v)
+ if len(l) > 1:
+ self.form.value.remove(self.form[key])
+ # replace the single value with the split list
+ for v in l:
+ self.form.value.append(cgi.MiniFieldStorage(key, v))
+
self.form.value.append(cgi.MiniFieldStorage('@filter', key))
# handle saving the query params
''' Extract a list of values from the form value.
It may be one of:
- [MiniFieldStorage, MiniFieldStorage, ...]
+ [MiniFieldStorage('value'), MiniFieldStorage('value','value',...), ...]
MiniFieldStorage('value,value,...')
MiniFieldStorage('value')
'''
# multiple values are OK
if isinstance(value, type([])):
- # it's a list of MiniFieldStorages
- value = [i.value.strip() for i in value]
+ # it's a list of MiniFieldStorages - join then into
+ values = ','.join([i.value.strip() for i in value])
else:
# it's a MiniFieldStorage, but may be a comma-separated list
# of values
- value = [i.strip() for i in value.value.split(',')]
+ values = value.value
+
+ value = [i.strip() for i in values.split(',')]
# filter out the empty bits
return filter(None, value)
index 4eacc8cc258846563f534b4a455cc4345ff074fe..b6cbdcc569242ee3207110aa6c15d3c3c61a2159 100644 (file)
if self.classname is not None:
props = db.getclass(self.classname).getprops()
for name in self.filter:
- if self.form.has_key(name):
- prop = props[name]
- fv = self.form[name]
- if (isinstance(prop, hyperdb.Link) or
- isinstance(prop, hyperdb.Multilink)):
- self.filterspec[name] = lookupIds(db, prop,
- handleListCGIValue(fv))
+ if not self.form.has_key(name):
+ continue
+ prop = props[name]
+ fv = self.form[name]
+ if (isinstance(prop, hyperdb.Link) or
+ isinstance(prop, hyperdb.Multilink)):
+ self.filterspec[name] = lookupIds(db, prop,
+ handleListCGIValue(fv))
+ else:
+ if isinstance(fv, type([])):
+ self.filterspec[name] = [v.value for v in fv]
else:
self.filterspec[name] = fv.value
diff --git a/test/test_cgi.py b/test/test_cgi.py
index d87f2ec6dc2888b16b618deb98cbe68829c73d91..92e0a58793a637c232ad1410e764be14aefde5bc 100644 (file)
--- a/test/test_cgi.py
+++ b/test/test_cgi.py
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
-# $Id: test_cgi.py,v 1.15 2003-04-17 06:51:44 richard Exp $
+# $Id: test_cgi.py,v 1.16 2003-05-09 01:47:50 richard Exp $
import unittest, os, shutil, errno, sys, difflib, cgi, re
self.assertEqual(self.parseForm({'nosy': 'admin,2'}, 'issue'),
({('issue', None): {'nosy': ['1','2']}}, []))
+ def testMixedMultilink(self):
+ form = cgi.FieldStorage()
+ form.list.append(cgi.MiniFieldStorage('nosy', '1,2'))
+ form.list.append(cgi.MiniFieldStorage('nosy', '3'))
+ cl = client.Client(self.instance, None, {'PATH_INFO':'/'}, form)
+ cl.classname = 'issue'
+ cl.nodeid = None
+ cl.db = self.db
+ self.assertEqual(cl.parsePropsFromForm(),
+ ({('issue', None): {'nosy': ['1','2', '3']}}, []))
+
def testEmptyMultilinkSet(self):
nodeid = self.db.issue.create(nosy=['1','2'])
self.assertEqual(self.parseForm({'nosy': ''}, 'issue', nodeid),
diff --git a/test/test_db.py b/test/test_db.py
index da9f3c7fdbbdb9c907125deec9e5282bf7bf84dc..0aa53fd406a7be1dbd569e59a037a27e9a128e86 100644 (file)
--- a/test/test_db.py
+++ b/test/test_db.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: test_db.py,v 1.88 2003-04-22 20:53:55 kedder Exp $
+# $Id: test_db.py,v 1.89 2003-05-09 01:47:51 richard Exp $
import unittest, os, shutil, time
def testFilteringString(self):
ae, filt = self.filteringSetup()
- ae(filt(None, {'title': 'issue one'}, ('+','id'), (None,None)), ['1'])
- ae(filt(None, {'title': 'issue'}, ('+','id'), (None,None)),
+ ae(filt(None, {'title': ['one']}, ('+','id'), (None,None)), ['1'])
+ ae(filt(None, {'title': ['issue']}, ('+','id'), (None,None)),
['1','2','3'])
+ ae(filt(None, {'title': ['one', 'two']}, ('+','id'), (None,None)),
+ ['1', '2'])
def testFilteringLink(self):
ae, filt = self.filteringSetup()