"""Route handlers for Vendor Bulk endpoints.""" from account.api import app from account.constants import error from account.constants.connectors import NEO4J_DATABASE_NAME from account.logic import ( vendor, ) from account.models import neo4j_vendor from account.utils.api_utils import validate_request_data from account.validation.schemas.lookup import ( LookupVendorsByUuids, LookupVendorsByVendorIds, ) from connector_neo4j import Neo4jSession from flask import Response, g, request from owsrequest import flask_request from owsresponse import response from owsresponse.adaptors.flask import flaskify @app.route('/vendors/dataloader', methods=['POST']) @Neo4jSession(use_v2=True, database=NEO4J_DATABASE_NAME) def get_vendors() -> Response: """Handler to get bulk vendors Expects JSON payload with a list of vendor uuids. Example payload: ['uuid1', 'uuid2'] Returns: Flask.response. """ vendor_uuids = request.get_json() if not isinstance(vendor_uuids, list) or not all( isinstance(item, str) for item in vendor_uuids ): return flaskify( response.create_error_response( error.ERROR_CODE_INVALID_INPUT, error.ERROR_MESSAGE_INVALID_REQUEST ) ) headers = request.headers.copy() authorization_header = next( (key for key in headers.keys() if key.lower() == 'authorization'), None ) if authorization_header: headers.pop(authorization_header, None) identity_id = g.request_context.identity_id profile_id = g.request_context.profile_id profile_type = g.request_context.profile_type access_rule_decision = flask_request.verify_rules_access_standalone(request) try: if not access_rule_decision: accessible_vendor_uuids = vendor.get_pp_accessible_vendors(vendor_uuids=vendor_uuids) else: accessible_vendor_uuids = neo4j_vendor.accessible_vendors( profile_id=profile_id, profile_type=profile_type, vendor_uuids=vendor_uuids, identity_id=identity_id, ) if len(accessible_vendor_uuids) != len(vendor_uuids): g.ows.log.warn( 'vendor-dataloader: called to access inaccessible vendor', resources={ 'profile': { 'profile_id': profile_id, 'profile_type': profile_type, 'identity_id': identity_id, }, 'headers': { 'profile_id': headers.get('Orchard-Profile-Id'), 'profile_type': headers.get('Orchard-Profile-Type'), 'identity_id': headers.get('Orchard-Identity-Id'), 'user_id': headers.get('Orchard-User-Id'), }, 'vendors': set(vendor_uuids) - set(accessible_vendor_uuids), 'input_vendors': vendor_uuids, 'accessible_vendors': accessible_vendor_uuids, }, ) return flaskify( response.Response( vendor.get_vendors( accessible_vendor_uuids=accessible_vendor_uuids, vendor_uuids=vendor_uuids ) ) ) except Exception as e: return flaskify(response.create_fatal_response(e.args)) @app.route('/vendors/names/dataloader', methods=['POST']) def get_vendors_names() -> Response: """Handler to get vendor names in bulk Expects JSON payload with a list of vendor uuids. Example payload: ['uuid1', 'uuid2'] Returns: Flask.response. """ vendor_uuids = request.get_json() if not isinstance(vendor_uuids, list) or not all( isinstance(item, str) for item in vendor_uuids ): return flaskify( response.create_error_response( error.ERROR_CODE_INVALID_INPUT, error.ERROR_MESSAGE_INVALID_REQUEST ) ) try: return flaskify(response.Response(vendor.get_vendor_names(vendor_uuids))) except Exception as e: return flaskify(response.create_fatal_response(e.args)) @app.route('/lookup/vendors/uuids/', methods=['POST']) @Neo4jSession(use_v2=True, database=NEO4J_DATABASE_NAME) @validate_request_data(LookupVendorsByUuids()) def lookup_vendors_by_uuids(): """Get list of vendor ids using their uuids. NOTE: This endpoint is configured to require NO access rule checks. This is because it is serving as a Policy Information Point for Permission Platform. Do not expose other properties or attributes via this endpoint. Returns: Flask.response. """ schema = LookupVendorsByUuids() request_payload = schema.load(request.get_json()) uuids = request_payload['uuids'] fetch_flags = request_payload.get('fetch_flags', []) if not uuids: return flaskify( response.create_error_response( error.ERROR_CODE_INVALID_INPUT, error.ERROR_MESSAGE_INVALID_REQUEST ) ) return flaskify(vendor.lookup_vendors_by_uuids(uuids, fetch_flags)) @app.route('/lookup/vendors/vendor-ids/', methods=['POST']) @Neo4jSession(use_v2=True, database=NEO4J_DATABASE_NAME) @validate_request_data(LookupVendorsByVendorIds()) def lookup_vendors_by_vendor_ids(): """Get list of vendor uuids using their vendor_ids. NOTE: This endpoint is configured to require NO access rule checks. This is because it is serving as a Policy Information Point for Permission Platform. Do not expose other properties or attributes via this endpoint. Returns: Flask.response. """ schema = LookupVendorsByVendorIds() request_payload = schema.load(request.get_json()) vendor_ids = request_payload['vendor_ids'] fetch_flags = request_payload.get('fetch_flags', []) if not vendor_ids: return flaskify( response.create_error_response( error.ERROR_CODE_INVALID_INPUT, error.ERROR_MESSAGE_INVALID_REQUEST ) ) return flaskify(vendor.lookup_vendors_by_vendor_ids(vendor_ids, fetch_flags)) @app.route('/vendors/by-external-identifier-1/', methods=['GET']) def get_vendors_by_external_identifier(external_identifier_1): """Get a list of vendors by external_identifier_1. Note: This endpoint is only for internal use in process of creation SME vendors. Args: external_identifier_1 (str): external_identifier_1. 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 ) ) owner_name = request.args.get('owner') result = vendor.get_vendors_by_external_identifier(external_identifier_1, owner_name) return flaskify(result)