Skip to content

Commit 0180c32

Browse files
committed
Change some 400 errors to 405 (method not allowed) errors where user is
tryng to delete or modify a read only attribute/resource. Fix errors generated when output dict include exceptions and we are generating XML output. Add XML header with encoding to xml output.
1 parent 03db880 commit 0180c32

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

roundup/rest.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ def put_attribute(self, class_name, item_id, attr_name, input):
10301030
except KeyError as message:
10311031
# key error returned for changing protected keys
10321032
# and changing invalid keys
1033-
raise UsageError(message)
1033+
raise AttributeError(message)
10341034

10351035
result = {
10361036
'id': item_id,
@@ -1150,7 +1150,7 @@ def delete_attribute(self, class_name, item_id, attr_name, input):
11501150
class_obj = self.db.getclass(class_name)
11511151
if attr_name not in class_obj.getprops(protected=False):
11521152
if attr_name in class_obj.getprops(protected=True):
1153-
raise UsageError("Attribute '%s' can not be updated " \
1153+
raise AttributeError("Attribute '%s' can not be deleted " \
11541154
"for class %s."%(attr_name, class_name))
11551155
else:
11561156
raise UsageError("Attribute '%s' not valid for class %s."%(
@@ -1326,7 +1326,7 @@ def patch_attribute(self, class_name, item_id, attr_name, input):
13261326
class_obj = self.db.getclass(class_name)
13271327
if attr_name not in class_obj.getprops(protected=False):
13281328
if attr_name in class_obj.getprops(protected=True):
1329-
raise UsageError("Attribute '%s' can not be updated " \
1329+
raise AttributeError("Attribute '%s' can not be updated " \
13301330
"for class %s."%(attr_name, class_name))
13311331

13321332
self.raise_if_no_etag(class_name, item_id, input)
@@ -1671,7 +1671,31 @@ def dispatch(self, method, uri, input):
16711671
output = RoundupJSONEncoder(indent=indent).encode(output)
16721672
elif data_type.lower() == "xml" and dicttoxml:
16731673
self.client.setHeader("Content-Type", "application/xml")
1674-
output = b2s(dicttoxml(output, root=False))
1674+
if 'error' in output:
1675+
# capture values in error with types unsupported
1676+
# by dicttoxml e.g. an exception, into something it
1677+
# can handle
1678+
import numbers
1679+
import collections
1680+
for key,val in output['error'].items():
1681+
if isinstance(val, numbers.Number) or type(val) in \
1682+
(str, unicode):
1683+
pass
1684+
elif hasattr(val, 'isoformat'): # datetime
1685+
pass
1686+
elif type(val) == bool:
1687+
pass
1688+
elif isinstance(val, dict):
1689+
pass
1690+
elif isinstance(val, collections.Iterable):
1691+
pass
1692+
elif val is None:
1693+
pass
1694+
else:
1695+
output['error'][key] = str(val)
1696+
1697+
output = '<?xml version="1.0" encoding="UTF-8" ?>\n' + \
1698+
b2s(dicttoxml(output, root=False))
16751699
else:
16761700
# FIXME?? consider moving this earlier. We should
16771701
# error out before doing any work if we can't

test/rest_common.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,15 +1085,15 @@ def testPutAttribute(self):
10851085
results = self.server.put_attribute(
10861086
'user', self.joeid, 'creator', form
10871087
)
1088-
expected= {'error': {'status': 400, 'msg':
1089-
UsageError('\'"creator", "actor", "creation" and '
1088+
expected= {'error': {'status': 405, 'msg':
1089+
AttributeError('\'"creator", "actor", "creation" and '
10901090
'"activity" are reserved\'')}}
10911091
print(results)
10921092
self.assertEqual(results['error']['status'],
10931093
expected['error']['status'])
10941094
self.assertEqual(type(results['error']['msg']),
10951095
type(expected['error']['msg']))
1096-
self.assertEqual(self.dummy_client.response_code, 400)
1096+
self.assertEqual(self.dummy_client.response_code, 405)
10971097

10981098
# put invalid property
10991099
# make sure we don't have permission issues
@@ -1272,15 +1272,15 @@ def testDeleteAttributeUri(self):
12721272
'issue', issue_id, 'creator', form
12731273
)
12741274
expected= {'error': {
1275-
'status': 400,
1276-
'msg': UsageError("Attribute 'creator' can not be updated for class issue.")
1275+
'status': 405,
1276+
'msg': AttributeError("Attribute 'creator' can not be updated for class issue.")
12771277
}}
12781278

12791279
self.assertEqual(results['error']['status'],
12801280
expected['error']['status'])
12811281
self.assertEqual(type(results['error']['msg']),
12821282
type(expected['error']['msg']))
1283-
self.assertEqual(self.dummy_client.response_code, 400)
1283+
self.assertEqual(self.dummy_client.response_code, 405)
12841284

12851285
# delete required property
12861286
etag = calculate_etag(self.db.issue.getnode(issue_id))

0 commit comments

Comments
 (0)