"""Common handlers - health, identity, validation, features, and reference data.""" import json from json import JSONDecodeError from connector_neo4j import Neo4jSession from flask import g, request from owsrequest import flask_request from owsresponse import response, status from owsresponse.adaptors.flask import flaskify from werkzeug.exceptions import HTTPException from account import config from account.api import app from account.connectors.sentry import sentry_client from account.constants import error, header from account.constants.connectors import NEO4J_DATABASE_NAME from account.logic import ( country, genre, identity as identity_logic, owner, region, vendor, ) from account.validation import validation @app.route(config.HEALTH_CHECK) def health(): """Check the health of the application.""" return flaskify(response.Response({'status': 'ok'})) @app.route('/identity', methods=['GET']) def identity(): """Get identity of account with a grass session. Returns: Flask.response: a dict of account info. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) grass_account_type, grass_account_id = flask_request.get_grass_headers(request) user_id = request.headers.get('Orchard-user-id') if not grass_account_type and not user_id: return flaskify(response.Response(status=401)) identity_response = identity_logic.get_identity(grass_account_type, grass_account_id) if not identity_response and user_id: identity_response = identity_logic.get_user_details(user_id) return flaskify(identity_response) @app.route('/distributor', methods=['HEAD']) def is_distributor_type(): """Validate Grass user is a distributor. Gets if vendor in Grass headers is a distributor. Returns: Flask.response. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) grass_account_type, grass_account_id = flask_request.get_grass_headers(request) validation = flask_request.verify_grass_access( request, required=True, vendor=grass_account_id, subaccount=grass_account_id ) if not validation: return flaskify(response=validation) if grass_account_type == header.GRASS_ACCOUNT_TYPE_SUBACCOUNT: return flaskify( response.create_error_response( error.ERROR_CODE_NOT_FOUND, error.ERROR_MESSAGE_NO_MATCH, status=204 ) ) data = vendor.is_distributor(grass_account_id) return flaskify(data) @app.route('/vendor-currency-codes', methods=['GET']) @validation.reject_grass_headers def get_all_vendor_currency_codes(): """Get a list of all currency codes for vendors. Returns: Flask.response: containing the list of all vendor currency codes. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(vendor.get_all_vendor_currency_codes()) @app.route('/owners', methods=['GET']) def get_owners(): """Get list of owners.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(owner.get_owners()) @app.route('/genres', methods=['GET']) def get_genres(): """Get list of genres from genre table. Returns: Flask.response. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(genre.get_genres()) @app.route('/countries', methods=['GET']) def get_countries(): """Get list of countries from country table. Returns: Flask.response. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(country.get_countries()) @app.route('/regions', methods=['GET']) def get_regions(): """Get list of regions from region table. Returns: Flask.response. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(region.get_regions()) @app.route('/service-tiers', methods=['GET']) @Neo4jSession(use_v2=True, database=NEO4J_DATABASE_NAME) def get_service_tiers(): """Get list of service tiers and uuids from service tier nodes in neo4j. Returns: Flask.response. """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, ) ) return flaskify(vendor.get_service_tiers()) @app.errorhandler(Exception) def exception_handler(error): """Handle error when uncaught exception is raised. Default exception handler. Returns: flask.Response: An error response. """ g.log.exception(error) # pass through HTTP errors if isinstance(error, HTTPException): sentry_client.capture_exception() return error # now you're handling non-HTTP exceptions only parsed_error = str(error) http_response_status = status.INTERNAL_ERROR response_code = 'bad_request' message = 'Bad Request' try: parsed_error = json.loads(parsed_error) http_response_status = parsed_error.get('status') or http_response_status response_code = parsed_error.get('code') or response_code message = parsed_error.get('message') or message except JSONDecodeError: message = parsed_error pass if http_response_status == status.INTERNAL_ERROR: sentry_client.capture_exception() return flaskify( response.create_error_response(response_code, message, status=http_response_status) )