"""Handler Utils. These are general purpose functions for use with all route handlers. """ from functools import wraps from flask import g from flask.json import jsonify from oto import response from oto.adaptors.flask import flaskify from owsresponse.response import create_error_response from project_manager.constant import error_const from project_manager.constant import header_const from project_manager.validation import json_schema def access_check(headers): """Determine whether this is an internal or external request. Logic is dependent on either, both, or neither Grass headers being there. Otherwise, authorization error. Args: headers (dict): a dict of the HTTP request headers from the request. Returns: account_type (string): grass account type or None. account_id (int): grass account id or None. """ account_type = headers.get(header_const.GRASS_ACCOUNT_TYPE) account_id = headers.get(header_const.GRASS_ACCOUNT_ID) if account_id: account_id = int(account_id) # if neither are set if not account_type and not account_id: return response.Response(message={ 'account_type': None, 'account_id': None}, status=200) # both must be set elif (not account_type) ^ (not account_id): return response.create_error_response( error_const.AUTHORIZATION_ERROR, 'Authorization error', status=403) # return values from grass headers return response.Response(message={ 'account_type': account_type, 'account_id': account_id}, status=200) def validate_header(request, validator): """A decorator to call when validating HTTP request headers. Args: request (werkzeug.local.LocalProxy): the request object from the handler. validator (Draft3Validator): the JSON Draft3 Schema to validate against. Returns: callable: the wrapped function. """ def decorator(f): @wraps(f) def _validate_header(*args, **kwargs): """Validate the request headers against a validator. Args: request (werkzeug.local.LocalProxy): the request object from the handler. validator (Draft3Validator): the JSON Draft3 Schema to validate against. Returns: Response: error HTTP response, or continue to the calling function if successful. """ validation_response = json_schema.validate( dict(request.headers), validator) if validation_response.status != 200: return flaskify(validation_response) return f(*args, **kwargs) return _validate_header return decorator def validate_body(request, validator): """A decorator to call when validating HTTP request body. Args: request (werkzeug.local.LocalProxy): the request object from the handler. validator (Draft3Validator): the JSON Draft3 Schema to validate against. Returns: callable: the wrapped function. """ def decorator(f): """Decorator for validate_body method.""" @wraps(f) def _validate_body(*args, **kwargs): """Validate the request body against a validator. Args: request (werkzeug.local.LocalProxy): the request object from the handler. validator (Draft3Validator): the JSON Draft3 Schema to validate against. Returns: Response: error HTTP response, or continue to the calling function if successful. """ validation_response = json_schema.validate( request.get_json(), validator) if validation_response.status != 200: return flaskify(validation_response) return f(*args, **kwargs) return _validate_body return decorator def get_error_json(request, error_code, error_detail, http_status_code): """Get Error from JSON.""" g.log.error('{}: {}'.format( error_code, error_detail)) error_json = { error_const.ERROR_CODE: error_code, error_const.ERROR_DETAIL: error_detail} response = jsonify(error_json) response.status_code = http_status_code correlation_id = request.headers.get(header_const.CORRELATION_ID) if correlation_id: response.headers[header_const.CORRELATION_ID] = correlation_id return response def validate_project_parameter(request): """A decorator to call when validating parameters for project. Args: request (werkzeug.local.LocalProxy): the request object from the handler. Returns: callable: the wrapped function. """ def decorator(f): @wraps(f) def _validate_project_parameter(*args, **kwargs): project_code = request.args.get('project_code') if not project_code: message = 'No project_code provided' return flaskify(create_error_response( error_const.VALIDATION_ERROR, message=message)) account_id = request.args.get('account_id', 0) subaccount_id = request.args.get('account_id', 0) if not (account_id or subaccount_id): message = 'No account_id or subaccount_id provided' return flaskify(create_error_response( error_const.VALIDATION_ERROR, message=message)) return f(*args, **kwargs) return _validate_project_parameter return decorator