import logging from flask import Blueprint, request from flask_restful import Resource, Api from flask_restful.utils.cors import crossdomain from email.utils import formatdate from calendar import timegm from functools import partial, wraps from jsonschema import validate, ValidationError from config_app.c_app import app from config_app.config_endpoints.exception import InvalidResponse, InvalidRequest logger = logging.getLogger(__name__) api_bp = Blueprint('api', __name__) CROSS_DOMAIN_HEADERS = ['Authorization', 'Content-Type', 'X-Requested-With'] class ApiExceptionHandlingApi(Api): pass @crossdomain(origin='*', headers=CROSS_DOMAIN_HEADERS) def handle_error(self, error): return super(ApiExceptionHandlingApi, self).handle_error(error) api = ApiExceptionHandlingApi() api.init_app(api_bp) def format_date(date): """ Output an RFC822 date format. """ if date is None: return None return formatdate(timegm(date.utctimetuple())) def resource(*urls, **kwargs): def wrapper(api_resource): if not api_resource: return None api_resource.registered = True api.add_resource(api_resource, *urls, **kwargs) return api_resource return wrapper class ApiResource(Resource): registered = False method_decorators = [] def options(self): return None, 200 def add_method_metadata(name, value): def modifier(func): if func is None: return None if '__api_metadata' not in dir(func): func.__api_metadata = {} func.__api_metadata[name] = value return func return modifier def method_metadata(func, name): if func is None: return None if '__api_metadata' in dir(func): return func.__api_metadata.get(name, None) return None def no_cache(f): @wraps(f) def add_no_cache(*args, **kwargs): response = f(*args, **kwargs) if response is not None: response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' return response return add_no_cache def define_json_response(schema_name): def wrapper(func): @add_method_metadata('response_schema', schema_name) @wraps(func) def wrapped(self, *args, **kwargs): schema = self.schemas[schema_name] resp = func(self, *args, **kwargs) if app.config['TESTING']: try: validate(resp, schema) except ValidationError as ex: raise InvalidResponse(ex.message) return resp return wrapped return wrapper def validate_json_request(schema_name, optional=False): def wrapper(func): @add_method_metadata('request_schema', schema_name) @wraps(func) def wrapped(self, *args, **kwargs): schema = self.schemas[schema_name] try: json_data = request.get_json() if json_data is None: if not optional: raise InvalidRequest('Missing JSON body') else: validate(json_data, schema) return func(self, *args, **kwargs) except ValidationError as ex: raise InvalidRequest(ex.message) return wrapped return wrapper nickname = partial(add_method_metadata, 'nickname') import config_endpoints.api import config_endpoints.api.discovery import config_endpoints.api.suconfig import config_endpoints.api.superuser import config_endpoints.api.user import config_endpoints.api.tar_config_loader