8abbe3462f
- Added support for Exception-specific HTTP response codes for AccountinExceptions.
90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
# Part of accounting-api project:
|
|
# https://gitorious.org/conservancy/accounting-api
|
|
# License: AGPLv3-or-later
|
|
|
|
from functools import wraps
|
|
|
|
from flask import jsonify, request
|
|
|
|
from accounting.exceptions import AccountingException
|
|
|
|
|
|
def jsonify_exceptions(func):
|
|
'''
|
|
Wraps a Flask endpoint and catches any AccountingException-based
|
|
exceptions which are returned to the client as JSON.
|
|
'''
|
|
@wraps(func)
|
|
def wrapper(*args, **kw):
|
|
try:
|
|
return func(*args, **kw)
|
|
except AccountingException as exc:
|
|
response = jsonify(error=exc)
|
|
|
|
response.status_code = exc.http_code
|
|
|
|
return response
|
|
|
|
return wrapper
|
|
|
|
|
|
def cors(origin_callback=None):
|
|
'''
|
|
Flask endpoint decorator.
|
|
|
|
Example:
|
|
|
|
.. code-block:: python
|
|
|
|
@app.route('/cors-endpoint', methods=['GET', 'OPTIONS'])
|
|
@cors()
|
|
def cors_endpoint():
|
|
return jsonify(message='This is accessible via a cross-origin XHR')
|
|
|
|
# Or if you want to control the domains this resource can be requested
|
|
# from via CORS:
|
|
domains = ['http://wandborg.se', 'http://sfconservancy.org']
|
|
|
|
def restrict_domains(origin):
|
|
return ' '.join(domains)
|
|
|
|
@app.route('/restricted-cors-endpoint')
|
|
@cors(restrict_domains)
|
|
def restricted_cors_endpoint():
|
|
return jsonify(
|
|
message='This is accessible from %s' % ', '.join(domains))
|
|
|
|
:param function origin_callback: A callback that takes one str() argument
|
|
containing the ``Origin`` HTTP header from the :data:`request` object.
|
|
This can be used to filter out which domains the resource can be
|
|
requested via CORS from.
|
|
'''
|
|
if origin_callback is None:
|
|
origin_callback = allow_all_origins
|
|
|
|
def decorator(func):
|
|
@wraps(func)
|
|
def wrapper(*args, **kw):
|
|
response = func(*args, **kw)
|
|
cors_headers = {
|
|
'Access-Control-Allow-Origin':
|
|
origin_callback(request.headers.get('Origin')) or '*',
|
|
'Access-Control-Allow-Credentials': 'true',
|
|
'Access-Control-Max-Age': 3600,
|
|
'Access-Control-Allow-Methods': 'POST, GET, DELETE',
|
|
'Access-Control-Allow-Headers':
|
|
'Accept, Content-Type, Connection, Cookie'
|
|
}
|
|
|
|
for key, val in cors_headers.items():
|
|
response.headers[key] = val
|
|
|
|
return response
|
|
|
|
return wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def allow_all_origins(origin):
|
|
return origin
|