Mercurial > kallithea
diff rhodecode/controllers/api/__init__.py @ 1794:702e29ce1e9b
backporting #329 into stable
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Wed, 21 Dec 2011 02:05:31 +0200 |
parents | 87ec80c280bb |
children | 419ad27763ab |
line wrap: on
line diff
--- a/rhodecode/controllers/api/__init__.py Wed Nov 02 23:23:53 2011 +0200 +++ b/rhodecode/controllers/api/__init__.py Wed Dec 21 02:05:31 2011 +0200 @@ -4,7 +4,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~ JSON RPC controller - + :created_on: Aug 20, 2011 :author: marcink :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> @@ -36,7 +36,7 @@ from paste.response import replace_header from pylons.controllers import WSGIController -from pylons.controllers.util import Response + from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \ HTTPBadRequest, HTTPError @@ -46,33 +46,40 @@ log = logging.getLogger('JSONRPC') + class JSONRPCError(BaseException): def __init__(self, message): self.message = message + super(JSONRPCError, self).__init__() def __str__(self): return str(self.message) def jsonrpc_error(message, code=None): - """Generate a Response object with a JSON-RPC error body""" - return Response(body=json.dumps(dict(result=None, - error=message))) + """ + Generate a Response object with a JSON-RPC error body + """ + from pylons.controllers.util import Response + resp = Response(body=json.dumps(dict(result=None, error=message)), + status=code, + content_type='application/json') + return resp class JSONRPCController(WSGIController): """ A WSGI-speaking JSON-RPC controller class - + See the specification: <http://json-rpc.org/wiki/specification>`. - + Valid controller return values should be json-serializable objects. - + Sub-classes should catch their exceptions and raise JSONRPCError if they want to pass meaningful errors to the client. - + """ def _get_method_args(self): @@ -104,24 +111,27 @@ try: json_body = json.loads(urllib.unquote_plus(raw_body)) except ValueError, e: - #catch JSON errors Here + # catch JSON errors Here return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \ % (e, urllib.unquote_plus(raw_body))) - #check AUTH based on API KEY + # check AUTH based on API KEY try: self._req_api_key = json_body['api_key'] + self._req_id = json_body['id'] self._req_method = json_body['method'] - self._req_params = json_body['args'] + self._request_params = json_body['args'] log.debug('method: %s, params: %s', self._req_method, - self._req_params) + self._request_params) except KeyError, e: return jsonrpc_error(message='Incorrect JSON query missing %s' % e) - #check if we can find this session using api_key + # check if we can find this session using api_key try: u = User.get_by_api_key(self._req_api_key) + if u is None: + return jsonrpc_error(message='Invalid API KEY') auth_u = AuthUser(u.user_id, self._req_api_key) except Exception, e: return jsonrpc_error(message='Invalid API KEY') @@ -136,13 +146,14 @@ # self.kargs and dispatch control to WGIController argspec = inspect.getargspec(self._func) arglist = argspec[0][1:] - defaults = argspec[3] or [] + defaults = map(type, argspec[3] or []) default_empty = types.NotImplementedType - kwarglist = list(izip_longest(reversed(arglist), reversed(defaults), - fillvalue=default_empty)) + # kw arguments required by this method + func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults), + fillvalue=default_empty)) - # this is little trick to inject logged in user for + # this is little trick to inject logged in user for # perms decorators to work they expect the controller class to have # rhodecode_user attribute set self.rhodecode_user = auth_u @@ -157,21 +168,23 @@ (self._func.__name__, USER_SESSION_ATTR)) # get our arglist and check if we provided them as args - for arg, default in kwarglist: + for arg, default in func_kwargs.iteritems(): if arg == USER_SESSION_ATTR: - # USER_SESSION_ATTR is something translated from api key and + # USER_SESSION_ATTR is something translated from api key and # this is checked before so we don't need validate it continue - # skip the required param check if it's default value is + # skip the required param check if it's default value is # NotImplementedType (default_empty) - if not self._req_params or (type(default) == default_empty - and arg not in self._req_params): - return jsonrpc_error(message=('Missing non optional %s arg ' - 'in JSON DATA') % arg) + if (default == default_empty and arg not in self._request_params): + return jsonrpc_error( + message=( + 'Missing non optional `%s` arg in JSON DATA' % arg + ) + ) - self._rpc_args = {USER_SESSION_ATTR:u} - self._rpc_args.update(self._req_params) + self._rpc_args = {USER_SESSION_ATTR: u} + self._rpc_args.update(self._request_params) self._rpc_args['action'] = self._req_method self._rpc_args['environ'] = environ @@ -180,6 +193,7 @@ status = [] headers = [] exc_info = [] + def change_content(new_status, new_headers, new_exc_info=None): status.append(new_status) headers.extend(new_headers) @@ -212,7 +226,8 @@ if self._error is not None: raw_response = None - response = dict(result=raw_response, error=self._error) + response = dict(result=raw_response, + error=self._error) try: return json.dumps(response)