Mercurial > kallithea
comparison rhodecode/controllers/api/__init__.py @ 1793:631caf880b87 beta
implements #329
- api function for adding a users_group into repo
- fixed found issues on API with missing params detection
- updated docs for api
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Wed, 21 Dec 2011 01:53:01 +0200 |
parents | fee9895fa46e |
children | 6274adc06988 |
comparison
equal
deleted
inserted
replaced
1792:2afa6b8c2ade | 1793:631caf880b87 |
---|---|
44 from rhodecode.model.db import User | 44 from rhodecode.model.db import User |
45 from rhodecode.lib.auth import AuthUser | 45 from rhodecode.lib.auth import AuthUser |
46 | 46 |
47 log = logging.getLogger('JSONRPC') | 47 log = logging.getLogger('JSONRPC') |
48 | 48 |
49 | |
49 class JSONRPCError(BaseException): | 50 class JSONRPCError(BaseException): |
50 | 51 |
51 def __init__(self, message): | 52 def __init__(self, message): |
52 self.message = message | 53 self.message = message |
53 super(JSONRPCError, self).__init__() | 54 super(JSONRPCError, self).__init__() |
65 status=code, | 66 status=code, |
66 content_type='application/json') | 67 content_type='application/json') |
67 return resp | 68 return resp |
68 | 69 |
69 | 70 |
70 | |
71 class JSONRPCController(WSGIController): | 71 class JSONRPCController(WSGIController): |
72 """ | 72 """ |
73 A WSGI-speaking JSON-RPC controller class | 73 A WSGI-speaking JSON-RPC controller class |
74 | 74 |
75 See the specification: | 75 See the specification: |
76 <http://json-rpc.org/wiki/specification>`. | 76 <http://json-rpc.org/wiki/specification>`. |
77 | 77 |
78 Valid controller return values should be json-serializable objects. | 78 Valid controller return values should be json-serializable objects. |
79 | 79 |
80 Sub-classes should catch their exceptions and raise JSONRPCError | 80 Sub-classes should catch their exceptions and raise JSONRPCError |
81 if they want to pass meaningful errors to the client. | 81 if they want to pass meaningful errors to the client. |
82 | 82 |
83 """ | 83 """ |
84 | 84 |
85 def _get_method_args(self): | 85 def _get_method_args(self): |
86 """ | 86 """ |
87 Return `self._rpc_args` to dispatched controller method | 87 Return `self._rpc_args` to dispatched controller method |
109 raw_body = environ['wsgi.input'].read(length) | 109 raw_body = environ['wsgi.input'].read(length) |
110 | 110 |
111 try: | 111 try: |
112 json_body = json.loads(urllib.unquote_plus(raw_body)) | 112 json_body = json.loads(urllib.unquote_plus(raw_body)) |
113 except ValueError, e: | 113 except ValueError, e: |
114 #catch JSON errors Here | 114 # catch JSON errors Here |
115 return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \ | 115 return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \ |
116 % (e, urllib.unquote_plus(raw_body))) | 116 % (e, urllib.unquote_plus(raw_body))) |
117 | 117 |
118 # check AUTH based on API KEY | 118 # check AUTH based on API KEY |
119 try: | 119 try: |
120 self._req_api_key = json_body['api_key'] | 120 self._req_api_key = json_body['api_key'] |
121 self._req_id = json_body['id'] | 121 self._req_id = json_body['id'] |
122 self._req_method = json_body['method'] | 122 self._req_method = json_body['method'] |
123 self._req_params = json_body['args'] | 123 self._request_params = json_body['args'] |
124 log.debug('method: %s, params: %s', | 124 log.debug('method: %s, params: %s', |
125 self._req_method, | 125 self._req_method, |
126 self._req_params) | 126 self._request_params) |
127 except KeyError, e: | 127 except KeyError, e: |
128 return jsonrpc_error(message='Incorrect JSON query missing %s' % e) | 128 return jsonrpc_error(message='Incorrect JSON query missing %s' % e) |
129 | 129 |
130 # check if we can find this session using api_key | 130 # check if we can find this session using api_key |
131 try: | 131 try: |
144 | 144 |
145 # now that we have a method, add self._req_params to | 145 # now that we have a method, add self._req_params to |
146 # self.kargs and dispatch control to WGIController | 146 # self.kargs and dispatch control to WGIController |
147 argspec = inspect.getargspec(self._func) | 147 argspec = inspect.getargspec(self._func) |
148 arglist = argspec[0][1:] | 148 arglist = argspec[0][1:] |
149 defaults = argspec[3] or [] | 149 defaults = map(type, argspec[3] or []) |
150 default_empty = types.NotImplementedType | 150 default_empty = types.NotImplementedType |
151 | 151 |
152 kwarglist = list(izip_longest(reversed(arglist), reversed(defaults), | 152 # kw arguments required by this method |
153 fillvalue=default_empty)) | 153 func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults), |
154 | 154 fillvalue=default_empty)) |
155 # this is little trick to inject logged in user for | 155 |
156 # this is little trick to inject logged in user for | |
156 # perms decorators to work they expect the controller class to have | 157 # perms decorators to work they expect the controller class to have |
157 # rhodecode_user attribute set | 158 # rhodecode_user attribute set |
158 self.rhodecode_user = auth_u | 159 self.rhodecode_user = auth_u |
159 | 160 |
160 # This attribute will need to be first param of a method that uses | 161 # This attribute will need to be first param of a method that uses |
165 return jsonrpc_error(message='This method [%s] does not support ' | 166 return jsonrpc_error(message='This method [%s] does not support ' |
166 'authentication (missing %s param)' % | 167 'authentication (missing %s param)' % |
167 (self._func.__name__, USER_SESSION_ATTR)) | 168 (self._func.__name__, USER_SESSION_ATTR)) |
168 | 169 |
169 # get our arglist and check if we provided them as args | 170 # get our arglist and check if we provided them as args |
170 for arg, default in kwarglist: | 171 for arg, default in func_kwargs.iteritems(): |
171 if arg == USER_SESSION_ATTR: | 172 if arg == USER_SESSION_ATTR: |
172 # USER_SESSION_ATTR is something translated from api key and | 173 # USER_SESSION_ATTR is something translated from api key and |
173 # this is checked before so we don't need validate it | 174 # this is checked before so we don't need validate it |
174 continue | 175 continue |
175 | 176 |
176 # skip the required param check if it's default value is | 177 # skip the required param check if it's default value is |
177 # NotImplementedType (default_empty) | 178 # NotImplementedType (default_empty) |
178 if not self._req_params or (type(default) == default_empty | 179 if (default == default_empty and arg not in self._request_params): |
179 and arg not in self._req_params): | 180 return jsonrpc_error( |
180 return jsonrpc_error(message=('Missing non optional %s arg ' | 181 message=( |
181 'in JSON DATA') % arg) | 182 'Missing non optional `%s` arg in JSON DATA' % arg |
182 | 183 ) |
183 self._rpc_args = {USER_SESSION_ATTR:u} | 184 ) |
184 self._rpc_args.update(self._req_params) | 185 |
186 self._rpc_args = {USER_SESSION_ATTR: u} | |
187 self._rpc_args.update(self._request_params) | |
185 | 188 |
186 self._rpc_args['action'] = self._req_method | 189 self._rpc_args['action'] = self._req_method |
187 self._rpc_args['environ'] = environ | 190 self._rpc_args['environ'] = environ |
188 self._rpc_args['start_response'] = start_response | 191 self._rpc_args['start_response'] = start_response |
189 | 192 |
190 status = [] | 193 status = [] |
191 headers = [] | 194 headers = [] |
192 exc_info = [] | 195 exc_info = [] |
196 | |
193 def change_content(new_status, new_headers, new_exc_info=None): | 197 def change_content(new_status, new_headers, new_exc_info=None): |
194 status.append(new_status) | 198 status.append(new_status) |
195 headers.extend(new_headers) | 199 headers.extend(new_headers) |
196 exc_info.append(new_exc_info) | 200 exc_info.append(new_exc_info) |
197 | 201 |