"""Application Handlers. Requests are redirected to handlers, which are responsible for getting information from the URL and passing it down to the logic layer. The way each layer talks to each other is through Response objects which defines the type status of the data and the data itself. Please note: the Orchard uses the term handlers over views as convention for clarity See: owsresponse.response for more details. """ from http import HTTPStatus import botocore import sentry_sdk from artwork import config from artwork.api import app from artwork.constants import error, permissions from artwork.constants import service as service_constants from artwork.exceptions.invalid_usage import InvalidUsageException from artwork.utils import exception from flask import g, jsonify, request from marshmallow import ValidationError from owsrequest import request as owsrequest from owsresponse import response from owsresponse.adaptors.flask import flaskify @app.errorhandler(InvalidUsageException) def invalid_usage_exception_handler(invalid_usage_exception): """Handle all thrown InvalidUsageExceptions. Args: invalid_usage_exception (InvalidUsageException): A thrown InvalidUsageException Returns: flask.Response: Error response. """ return flaskify(invalid_usage_exception.response) @app.errorhandler(Exception) def exception_handler(err): """Handle error when uncaught exception is raised. Default exception handler. Note: Exception will also be sent to Sentry if config.SENTRY_DSN is set. Returns: flask.Response: A 400 or 500 response with JSON 'code' & 'message' payload. """ bad_request_message = 'Oopsies, I don\'t know how to respond to that ¯\\_(ツ)_/¯' bad_request_response = response.create_error_response( HTTPStatus.BAD_REQUEST, bad_request_message ) internal_server_error_message = ( 'I have erred and am unable to complete your request.' ) internal_server_error_response = response.create_fatal_response( internal_server_error_message ) if isinstance(err, ValidationError): return flaskify( response.create_error_response( code=error.ERROR_CODE_VALIDATION_ERROR, message={'error': err.messages} ) ) if ( isinstance(err, botocore.exceptions.ClientError) and (err.response.get('Error') or {}).get('Code') == 'NoSuchKey' ): return flaskify(bad_request_response) sentry_sdk.capture_exception() g.log.exception(err) if getattr(err, 'code', None) in range( HTTPStatus.BAD_REQUEST, HTTPStatus.INTERNAL_SERVER_ERROR ): return flaskify(bad_request_response) return flaskify(internal_server_error_response) @app.route(config.HEALTH_CHECK, methods=['GET']) def health(): """Check the health of the application.""" return jsonify({'status': 'ok'}) def get_vendor_and_subaccount(profile_type, profile_id): """Get vendor and subaccount. Args: profile_type (string): Profile type. profile_id (int): Profile id. Returns: (int, int): The tuple: (vendor_id, subaccount_id). """ ows_permissions_response = owsrequest.get( service_constants.OWS_PERMISSIONS, service_constants.OWS_PERMISSIONS_PROFILE_RESOURCE.format( profile_type=profile_type, profile_id=profile_id, resource='label' ), ) if ows_permissions_response.status_code != 200: exception.raise_exception(Exception, ows_permissions_response.status_code) return resources = ows_permissions_response.json()['items'] # Pull the first reference to a vendor or subaccount resource from result resource = next( ( resource for resource in resources if resource['type'].lower() in ( permissions.SUBACCOUNT_RESOURCE_TYPE.lower(), permissions.VENDOR_RESOURCE_TYPE.lower(), ) ), None, ) # If no vendor or subaccount resources, return no vendor_id, subaccount_id if not resource: return None, None # If the resource is a vendor, return only vendor_id if resource['type'] == permissions.VENDOR_RESOURCE_TYPE: return resource['id'], None # Return vendor_id, subaccount_id return resource['vendor_id'], resource['id'] def _is_public_request(): """Check if this request is public and it doesn't require context check.""" return False def _get_query_vendor_and_subaccount(): """Get vendor and subaccount from request params.""" request_params = { **request.args.to_dict(), **(request.get_json(silent=True) or {}), } vendor_id = int(request_params.get('vendor_id', 0)) subaccount_id = int(request_params.get('subaccount_id', 0)) return vendor_id, subaccount_id @app.after_request def after_request(resp): """Prepare the response.""" return resp