Feed error messages through a cors wrapper so that people on other domains can see what's happening.
This commit is contained in:
parent
4673f40dd2
commit
3b3d71bfd7
18 changed files with 162 additions and 129 deletions
|
@ -1,9 +1,10 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from flask import Blueprint, request
|
||||
from flask import Blueprint, request, make_response, jsonify
|
||||
from flask.ext.restful import Resource, abort, Api, reqparse
|
||||
from flask.ext.restful.utils.cors import crossdomain
|
||||
from werkzeug.exceptions import HTTPException
|
||||
from calendar import timegm
|
||||
from email.utils import formatdate
|
||||
from functools import partial, wraps
|
||||
|
@ -27,6 +28,57 @@ api.decorators = [process_oauth,
|
|||
crossdomain(origin='*', headers=['Authorization', 'Content-Type'])]
|
||||
|
||||
|
||||
class ApiException(Exception):
|
||||
def __init__(self, error_type, status_code, error_description, payload=None):
|
||||
Exception.__init__(self)
|
||||
self.error_description = error_description
|
||||
self.status_code = status_code
|
||||
self.payload = payload
|
||||
self.error_type = error_type
|
||||
|
||||
def to_dict(self):
|
||||
rv = dict(self.payload or ())
|
||||
if self.error_description is not None:
|
||||
rv['error_description'] = self.error_description
|
||||
|
||||
rv['error_type'] = self.error_type
|
||||
return rv
|
||||
|
||||
|
||||
invalid_request = partial(ApiException, 'invalid_request', 400)
|
||||
|
||||
|
||||
class InvalidRequest(ApiException):
|
||||
def __init__(self, error_description, payload=None):
|
||||
ApiException.__init__(self, 'invalid_request', 400, error_description, payload)
|
||||
|
||||
|
||||
class InvalidToken(ApiException):
|
||||
def __init__(self, error_description, payload=None):
|
||||
ApiException.__init__(self, 'invalid_token', 401, error_description, payload)
|
||||
|
||||
|
||||
class Unauthorized(ApiException):
|
||||
def __init__(self, payload=None):
|
||||
ApiException.__init__(self, 'insufficient_scope', 403, 'Unauthorized', payload)
|
||||
|
||||
|
||||
class NotFound(ApiException):
|
||||
def __init__(self, payload=None):
|
||||
ApiException.__init__(self, None, 404, 'Not Found', payload)
|
||||
|
||||
|
||||
@api_bp.app_errorhandler(ApiException)
|
||||
@crossdomain(origin='*', headers=['Authorization', 'Content-Type'])
|
||||
def handle_api_error(error):
|
||||
response = jsonify(error.to_dict())
|
||||
response.status_code = error.status_code
|
||||
if error.error_type is not None:
|
||||
response.headers['WWW-Authenticate'] = ('Bearer error="%s" error_description="%s"' %
|
||||
(error.error_type, error.error_description))
|
||||
return response
|
||||
|
||||
|
||||
def resource(*urls, **kwargs):
|
||||
def wrapper(api_resource):
|
||||
api.add_resource(api_resource, *urls, **kwargs)
|
||||
|
@ -84,7 +136,7 @@ def parse_args(func):
|
|||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if '__api_query_params' not in dir(func):
|
||||
abort(400)
|
||||
abort(500)
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
for arg_spec in func.__api_query_params:
|
||||
|
@ -124,7 +176,7 @@ def require_repo_permission(permission_class, scope, allow_public=False):
|
|||
(allow_public and
|
||||
model.repository_is_public(namespace, repository))):
|
||||
return func(self, namespace, repository, *args, **kwargs)
|
||||
abort(403)
|
||||
raise Unauthorized()
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
||||
|
@ -154,17 +206,14 @@ def validate_json_request(schema_name):
|
|||
validate(request.get_json(), schema)
|
||||
return func(self, *args, **kwargs)
|
||||
except ValidationError as ex:
|
||||
abort(400, message=ex.message)
|
||||
InvalidRequest(ex.message)
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
||||
|
||||
def request_error(exception=None, **kwargs):
|
||||
data = kwargs.copy()
|
||||
if exception:
|
||||
data['message'] = exception.message
|
||||
|
||||
return json.dumps(data), 400
|
||||
raise InvalidRequest(exception.message, data)
|
||||
|
||||
|
||||
def log_action(kind, user_or_orgname, metadata={}, repo=None):
|
||||
|
|
Reference in a new issue