Skip to content

Commit 9123586

Browse files
author
Richard Jones
committed
- more fixes to CGI form handling
- switch metakit to use "compressed" multilink journal change representation
1 parent 397cc6f commit 9123586

File tree

4 files changed

+104
-13
lines changed

4 files changed

+104
-13
lines changed

CHANGES.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ are given with the most recent entry first.
1212
- cleaning old unused sessions only once per hour, not on every cgi
1313
request. It is greatly improves web interface performance, especially
1414
on trackers under high load
15-
- fix StringHTMLProperty hyperlinking
1615
- added mysql backend
17-
- fixes to CGI form handling (NEEDS BACKPORTING TO 0.5)
16+
- fixes to CGI form handling
17+
- switch metakit to use "compressed" multilink journal change representation
1818
- applied unicode patch. All data is stored in utf-8. Incoming messages
1919
converted from any encoding to utf-8, outgoing messages are encoded
2020
according to rfc2822 (sf bug 568873)

roundup/backends/back_metakit.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,8 @@ def set(self, nodeid, **propvalues):
475475
if self.do_journal and prop.do_journal:
476476
self.db.addjournal(link_class, id, _LINK,
477477
(self.classname, str(row.id), key))
478-
478+
479+
# perform the modifications on the actual property value
479480
sv = getattr(row, key)
480481
i = 0
481482
while i < len(sv):
@@ -485,7 +486,17 @@ def set(self, nodeid, **propvalues):
485486
i += 1
486487
for id in adds:
487488
sv.append(fid=int(id))
488-
changes[key] = oldvalue
489+
490+
# figure the journal entry
491+
l = []
492+
if adds:
493+
l.append(('+', adds))
494+
if rmvd:
495+
l.append(('-', rmvd))
496+
if l:
497+
changes[key] = tuple(l)
498+
#changes[key] = oldvalue
499+
489500
if not rmvd and not adds:
490501
del propvalues[key]
491502

roundup/cgi/client.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: client.py,v 1.70 2003-01-15 11:14:01 richard Exp $
1+
# $Id: client.py,v 1.71 2003-01-15 22:39:07 richard Exp $
22

33
__doc__ = """
44
WWW request handler (also used in the stand-alone server).
@@ -1221,9 +1221,10 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
12211221

12221222
# does the property exist?
12231223
if not properties.has_key(propname):
1224-
if mlaction == 'remove':
1225-
raise ValueError, 'You have submitted a remove action for'\
1226-
' the property "%s" which doesn\'t exist'%propname
1224+
if mlaction != 'set':
1225+
raise ValueError, 'You have submitted a %s action for'\
1226+
' the property "%s" which doesn\'t exist'%(mlaction,
1227+
propname)
12271228
continue
12281229
proptype = properties[propname]
12291230

@@ -1281,7 +1282,7 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
12811282
value = None
12821283
elif isinstance(proptype, hyperdb.Link):
12831284
# see if it's the "no selection" choice
1284-
if value == '-1':
1285+
if value == '-1' or not value:
12851286
# if we're creating, just don't include this property
12861287
if not nodeid:
12871288
continue

test/test_cgi.py

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# but WITHOUT ANY WARRANTY; without even the implied warranty of
99
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1010
#
11-
# $Id: test_cgi.py,v 1.4 2003-01-15 11:14:01 richard Exp $
11+
# $Id: test_cgi.py,v 1.5 2003-01-15 22:39:07 richard Exp $
1212

1313
import unittest, os, shutil, errno, sys, difflib, cgi
1414

@@ -58,9 +58,14 @@ def testNothing(self):
5858
makeForm({})), {})
5959

6060
def testNothingWithRequired(self):
61-
form = makeForm({':required': 'title'})
6261
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
63-
self.db.issue, form)
62+
self.db.issue, makeForm({':required': 'title'}))
63+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
64+
self.db.issue, makeForm({':required': 'title,status',
65+
'status':'1'}))
66+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
67+
self.db.issue, makeForm({':required': ['title','status'],
68+
'status':'1'}))
6469

6570
#
6671
# String
@@ -87,6 +92,38 @@ def testEmptyStringSet(self):
8792
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
8893
makeForm({'title': ' '}), nodeid), {'title': ''})
8994

95+
#
96+
# Link
97+
#
98+
def testEmptyLink(self):
99+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
100+
makeForm({'status': ''})), {})
101+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
102+
makeForm({'status': ' '})), {})
103+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
104+
self.db.issue, makeForm({'status': ['', '']}))
105+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
106+
makeForm({'status': '-1'})), {})
107+
108+
def testSetLink(self):
109+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
110+
makeForm({'status': 'unread'})), {'status': '1'})
111+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
112+
makeForm({'status': '1'})), {'status': '1'})
113+
114+
def testUnsetLink(self):
115+
nodeid = self.db.issue.create(status='unread')
116+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
117+
makeForm({'status': '-1'}), nodeid), {'status': None})
118+
119+
def testInvalidLinkValue(self):
120+
# XXX This is not the current behaviour - should we enforce this?
121+
# self.assertRaises(IndexError, client.parsePropsFromForm, self.db,
122+
# self.db.issue, makeForm({'status': '4'}))
123+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
124+
self.db.issue, makeForm({'status': 'frozzle'}))
125+
# XXX need a test for the TypeError where the link class doesn't define a key?
126+
90127
#
91128
# Multilink
92129
#
@@ -124,7 +161,7 @@ def testInvalidMultilinkValue(self):
124161
self.db.issue, makeForm({'nosy': 'frozzle'}))
125162
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
126163
self.db.issue, makeForm({'nosy': '1,frozzle'}))
127-
# XXX need a test for the TypeError (where the ML class doesn't define a key
164+
# XXX need a test for the TypeError (where the ML class doesn't define a key?
128165

129166
def testMultilinkAdd(self):
130167
nodeid = self.db.issue.create(nosy=['1'])
@@ -162,6 +199,22 @@ def testMultilinkRemove(self):
162199
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
163200
self.db.issue, makeForm({':remove:nosy': '4'}), nodeid)
164201

202+
def testMultilinkRetired(self):
203+
self.db.user.retire('2')
204+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
205+
makeForm({'nosy': ['2','3']})), {'nosy': ['2','3']})
206+
nodeid = self.db.issue.create(nosy=['1','2'])
207+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
208+
makeForm({':remove:nosy': '2'}), nodeid), {'nosy': ['1']})
209+
self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
210+
makeForm({':add:nosy': '3'}), nodeid), {'nosy': ['1','2','3']})
211+
212+
def testAddRemoveNonexistant(self):
213+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
214+
self.db.issue, makeForm({':remove:foo': '2'}))
215+
self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
216+
self.db.issue, makeForm({':add:foo': '2'}))
217+
165218
#
166219
# Password
167220
#
@@ -196,6 +249,32 @@ def testEmptyPasswordNOTSet(self):
196249
self.assertEqual(client.parsePropsFromForm(self.db, self.db.user,
197250
makeForm({'password': '', 'password:confirm': ''}), nodeid), {})
198251

252+
#
253+
# Boolean
254+
#
255+
# XXX this needs a property to work on.
256+
# def testEmptyBoolean(self):
257+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
258+
# makeForm({'title': ''})), {})
259+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
260+
# makeForm({'title': ' '})), {})
261+
# self.assertRaises(ValueError, client.parsePropsFromForm, self.db,
262+
# self.db.issue, makeForm({'title': ['', '']}))
263+
264+
# def testSetBoolean(self):
265+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
266+
# makeForm({'title': 'foo'})), {'title': 'foo'})
267+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
268+
# makeForm({'title': 'a\r\nb\r\n'})), {'title': 'a\nb'})
269+
270+
# def testEmptyBooleanSet(self):
271+
# nodeid = self.db.issue.create(title='foo')
272+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
273+
# makeForm({'title': ''}), nodeid), {'title': ''})
274+
# nodeid = self.db.issue.create(title='foo')
275+
# self.assertEqual(client.parsePropsFromForm(self.db, self.db.issue,
276+
# makeForm({'title': ' '}), nodeid), {'title': ''})
277+
199278

200279
def suite():
201280
l = [unittest.makeSuite(FormTestCase),

0 commit comments

Comments
 (0)