Files @ 8abbe3462fda
Branch filter:

Location: NPO-Accounting/experimental-accounting-api/accounting/decorators.py

Joar Wandborg
[tests] Check transactions for errors before being added

- Added support for Exception-specific HTTP response codes for
AccountinExceptions.
# 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