Mercurial > p > roundup > code
comparison roundup/rest.py @ 5559:3d80e7752783 REST-rebased
Added POST and DELETE
[[Ralf Schlatterbeck: Add *all* http methods in roundup_server.py as
done on the bugs.python.org branch]]
committer: Ralf Schlatterbeck <rsc@runtux.com>
| author | Chau Nguyen <dangchau1991@yahoo.com> |
|---|---|
| date | Wed, 30 Jan 2019 10:25:12 +0100 |
| parents | 1bef1076ad12 |
| children | 2cc07def1b3f |
comparison
equal
deleted
inserted
replaced
| 5558:1bef1076ad12 | 5559:3d80e7752783 |
|---|---|
| 7 | 7 |
| 8 import json | 8 import json |
| 9 import pprint | 9 import pprint |
| 10 from roundup import hyperdb | 10 from roundup import hyperdb |
| 11 from roundup.cgi.templating import Unauthorised | 11 from roundup.cgi.templating import Unauthorised |
| 12 from roundup import xmlrpc | |
| 12 | 13 |
| 13 | 14 |
| 14 class RestfulInstance(object): | 15 class RestfulInstance(object): |
| 15 """Dummy Handler for REST | 16 """Dummy Handler for REST |
| 17 WARNING: Very ugly !!!!, cleaned & better organized in progress (next commit) | |
| 16 """ | 18 """ |
| 17 | 19 |
| 18 def __init__(self, db): | 20 def __init__(self, db): |
| 19 # TODO: database, translator and instance.actions | 21 # TODO: database, translator and instance.actions |
| 20 self.db = db | 22 self.db = db |
| 23 # TODO: split this into collection URI and resource URI | 25 # TODO: split this into collection URI and resource URI |
| 24 class_name = resource_uri | 26 class_name = resource_uri |
| 25 try: | 27 try: |
| 26 class_obj = self.db.getclass(class_name) | 28 class_obj = self.db.getclass(class_name) |
| 27 """prop_name = class_obj.labelprop() | 29 """prop_name = class_obj.labelprop() |
| 28 result = [class_obj.get(item_id, prop_name) | 30 result = [class_obj.get(item_id, prop_name)""" |
| 29 for item_id in class_obj.list() | |
| 30 if self.db.security.hasPermission('View', self.db.getuid(), | |
| 31 class_name, prop_name, item_id) | |
| 32 ] | |
| 33 result = json.JSONEncoder().encode(result)""" | |
| 34 result = [{'id': item_id} | 31 result = [{'id': item_id} |
| 35 for item_id in class_obj.list() | 32 for item_id in class_obj.list() |
| 36 if self.db.security.hasPermission('View', self.db.getuid(), | 33 if self.db.security.hasPermission('View', |
| 37 class_name, None, item_id) | 34 self.db.getuid(), |
| 35 class_name, | |
| 36 None, | |
| 37 item_id) | |
| 38 ] | 38 ] |
| 39 result = json.JSONEncoder().encode(result) | 39 result = json.JSONEncoder().encode(result) |
| 40 #result = `len(dict(result))` + ' ' + `len(result)` | 40 # result = `len(dict(result))` + ' ' + `len(result)` |
| 41 except KeyError: | 41 except KeyError: |
| 42 pass | 42 pass |
| 43 | 43 |
| 44 try: | 44 try: |
| 45 class_name, item_id = hyperdb.splitDesignator(resource_uri) | 45 class_name, item_id = hyperdb.splitDesignator(resource_uri) |
| 46 class_obj = self.db.getclass(class_name) | 46 class_obj = self.db.getclass(class_name) |
| 47 props = class_obj.properties.keys() | 47 props = class_obj.properties.keys() |
| 48 props.sort() | 48 props.sort() |
| 49 result = [(prop_name, class_obj.get(item_id, prop_name)) | 49 result = [(prop_name, class_obj.get(item_id, prop_name)) |
| 50 for prop_name in props | 50 for prop_name in props |
| 51 if self.db.security.hasPermission('View', self.db.getuid(), | 51 if self.db.security.hasPermission('View', |
| 52 class_name, prop_name, item_id) | 52 self.db.getuid(), |
| 53 class_name, | |
| 54 prop_name, | |
| 55 item_id) | |
| 53 ] | 56 ] |
| 54 # Note: is this a bug by having an extra indent in xmlrpc ? | 57 # Note: is this a bug by having an extra indent in xmlrpc ? |
| 55 result = json.JSONEncoder().encode(dict(result)) | 58 result = json.JSONEncoder().encode(dict(result)) |
| 56 except hyperdb.DesignatorError: | 59 except hyperdb.DesignatorError: |
| 57 pass | 60 pass |
| 58 | 61 |
| 59 # print type(result) | |
| 60 # print type(dict(result)) | |
| 61 return result | 62 return result |
| 62 # return json.dumps(dict(result)) | 63 |
| 63 # return dict(result) | 64 def action_post(self, resource_uri, input): |
| 65 class_name = resource_uri | |
| 66 | |
| 67 if not self.db.security.hasPermission('Create', self.db.getuid(), | |
| 68 class_name): | |
| 69 raise Unauthorised('Permission to create %s denied' % class_name) | |
| 70 | |
| 71 class_obj = self.db.getclass(class_name) | |
| 72 | |
| 73 # convert types | |
| 74 props = xmlrpc.props_from_args(self.db, class_obj, input) | |
| 75 | |
| 76 # check for the key property | |
| 77 key = class_obj.getkey() | |
| 78 if key and key not in props: | |
| 79 raise xmlrpc.UsageError, 'Must provide the "%s" property.' % key | |
| 80 | |
| 81 for key in props: | |
| 82 if not self.db.security.hasPermission('Create', self.db.getuid(), | |
| 83 class_name, property=key): | |
| 84 raise Unauthorised('Permission to create %s.%s denied' % | |
| 85 (class_name, key)) | |
| 86 | |
| 87 # do the actual create | |
| 88 try: | |
| 89 result = class_obj.create(**props) | |
| 90 self.db.commit() | |
| 91 except (TypeError, IndexError, ValueError), message: | |
| 92 raise xmlrpc.UsageError, message | |
| 93 return result | |
| 94 | |
| 95 def action_put(self, resource_uri, input): | |
| 96 raise NotImplementedError | |
| 97 | |
| 98 def action_delete(self, resource_uri, input): | |
| 99 # TODO: should I allow user to delete the whole collection ? | |
| 100 # TODO: BUG with DELETE without form data. Working with random data | |
| 101 class_name = resource_uri | |
| 102 try: | |
| 103 class_obj = self.db.getclass(class_name) | |
| 104 raise NotImplementedError | |
| 105 except KeyError: | |
| 106 pass | |
| 107 | |
| 108 try: | |
| 109 class_name, item_id = hyperdb.splitDesignator(resource_uri) | |
| 110 print class_name | |
| 111 print item_id | |
| 112 self.db.destroynode(class_name, item_id) | |
| 113 result = 'OK' | |
| 114 except IndexError: | |
| 115 result = 'Error' | |
| 116 except hyperdb.DesignatorError: | |
| 117 pass | |
| 118 | |
| 119 return result | |
| 120 | |
| 121 def action_patch(self, resource_uri, input): | |
| 122 raise NotImplementedError | |
| 64 | 123 |
| 65 def dispatch(self, method, uri, input): | 124 def dispatch(self, method, uri, input): |
| 66 print "METHOD: " + method + " URI: " + uri | 125 print "METHOD: " + method + " URI: " + uri |
| 67 print type(input) | 126 print type(input) |
| 68 pprint.pprint(input) | 127 pprint.pprint(input) |
| 72 # 1 - resource | 131 # 1 - resource |
| 73 # | 132 # |
| 74 # Example: rest/issue - collection uri | 133 # Example: rest/issue - collection uri |
| 75 # Example: rest/issue573 - element uri | 134 # Example: rest/issue573 - element uri |
| 76 uri_path = uri.split("/") | 135 uri_path = uri.split("/") |
| 136 input_form = ["%s=%s" % (item.name, item.value) for item in input] | |
| 137 # TODO: process input_form directly instead of making a new array | |
| 138 # TODO: rest server | |
| 77 # TODO: use named function for this instead | 139 # TODO: use named function for this instead |
| 78 # TODO: check roundup/actions.py | 140 # TODO: check roundup/actions.py |
| 79 # TODO: if uri_path has more than 2 child, return 404 | 141 # TODO: if uri_path has more than 2 child, return 404 |
| 142 # TODO: custom JSONEncoder to handle other data type | |
| 143 # TODO: catch all error and display error. | |
| 80 output = "METHOD is not supported" | 144 output = "METHOD is not supported" |
| 81 if method == "GET": | 145 if method == "GET": |
| 82 output = self.action_get(uri_path[1], input) | 146 output = self.action_get(uri_path[1], input_form) |
| 83 elif method == "POST": | 147 elif method == "POST": |
| 84 pass | 148 output = self.action_post(uri_path[1], input_form) |
| 85 elif method == "PUT": | 149 elif method == "PUT": |
| 86 pass | 150 output = self.action_put(uri_path[1], input_form) |
| 87 elif method == "DELETE": | 151 elif method == "DELETE": |
| 88 pass | 152 output = self.action_delete(uri_path[1], input_form) |
| 89 elif method == "PATCH": | 153 elif method == "PATCH": |
| 90 pass | 154 output = self.action_patch(uri_path[1], input_form) |
| 91 else: | 155 else: |
| 92 pass | 156 pass |
| 93 | 157 |
| 94 print "Response Length: " + `len(output)` + " - Response Content (First 50 char): " + output[:50] | 158 print "Response Length: %s - Response Content (First 50 char): %s" %\ |
| 159 (len(output), output[:50]) | |
| 95 return output | 160 return output |
