"""Elasticsearch search queries for conflicts.""" import boto3 from opensearchpy import OpenSearch, Q as QOpen, \ RequestsHttpConnection as RequestsHttpConnectionOpenSearch, \ Search as SearchOpen from oto import response from requests_aws4auth import AWS4Auth from conflict_manager import config from conflict_manager.constants import conflict as conflict_const from conflict_manager.constants import error from conflict_manager.constants import schema from conflict_manager.utils import api_utils _SORT_FIELD_TO_ELASTIC_SEARCH_KEYWORD = { 'track_name': 'track_name.keyword', 'track_artist_names': 'track_artists.keyword', 'product_name': 'product_name.keyword', 'conflicting_owner_name': 'conflicting_owner.keyword', 'subaccount_name': 'subaccount_name.keyword' } def get_new_conflicts_for_account( account, query=None, fields=[], sort_by=None, sort_order='asc', offset=0, limit=50): """Get list of new conflicts via Elasticsearch. Args: account (namedtuple): User account data query_args (ImmutableMultiDict): GET query arguments sort_by (str): Field to sort results by sort_order (str): Order results by ascending or descending offset (int): Number of items to skip limit (int): Max results to return Returns: response.Response: dict of created action or errors """ # Filter by account and set sort parameters account_id_field = '{}_id'.format(account.type) s = SearchOpen(index=config.OPENSEARCH_NEW_CONFLICTS_INDEX).filter( 'term', **{account_id_field: account.id}).filter( 'term', **{schema.STATUS: conflict_const.STATUS_NEW.lower()}) s = _sort_search_query(s, sort_by, sort_order) if query and fields: q = QOpen('multi_match', query=query, fields=fields, operator='AND') s = s.query(q) # Set pagination options and execute results = s[offset:offset + limit].execute() items = [] for hit in results.hits: conflict = hit.to_dict() # Add ElasticSearch ID to data conflict['es_id'] = hit.meta.id del conflict['resolved_datetime'] items.append(conflict) total = results.hits.total.value return api_utils.make_pagination_response( items, offset, limit, total) def get_new_conflict_count_for_account(account): """Get count of new conflicts via ElasticSearch. Args: account (namedtuple): user account data Returns: response.Response: count of new conflicts for account. """ # Count documents filtered by account account_id_field = '{}_id'.format(account.type) query = {'query': {'match': {account_id_field: account.id}}} os_client = _get_opensearch_client() total_count = os_client.count( index=config.OPENSEARCH_NEW_CONFLICTS_INDEX, body=query)['count'] res = { 'pagination': { 'type': 'standard', 'offset': 0, 'limit': 0, 'total_records': total_count }, 'items': [] } return response.Response(res, status=200) def delete_conflict(account, es_id_list): """Delete a list of conflicts. Args: account (namedtuple): User account data es_id_list(list): List of elasticsearch _id's Returns: response.Response: bool of success """ account_id_field = '{}_id'.format(account.type) query_list = [] s = SearchOpen(index=config.OPENSEARCH_NEW_CONFLICTS_INDEX).filter( 'term', **{account_id_field: account.id}) # Form the query parameters for es_id in es_id_list: if es_id: query_list.append(QOpen('match', _id=es_id)) # Construct the query, mandating minimum one match q = QOpen('bool', should=query_list, minimum_should_match=1) s = s.query(q) results = s[:len(es_id_list)].execute() if (not len(results.hits)): return response.create_error_response( status=404, code=error.ERROR_CODE_NOT_FOUND, message=error.NO_MATCHING_IDS_MSG) s.delete() return response.Response( message="_id's deleted: \n{}".format(',\n'.join(es_id_list)), status=200) def _sort_search_query(search, sort_by, sort_order): """Sort the search query.""" sort_by = _SORT_FIELD_TO_ELASTIC_SEARCH_KEYWORD.get(sort_by, sort_by) sort_by_prefix = '-' if sort_order == 'desc' else '' sort_list = [sort_by_prefix + sort_by] if sort_by != 'conflict_date': sort_list.append('conflict_date') sort_list += ['tuid', 'conflicting_owner.keyword'] return search.sort(*sort_list) def _get_opensearch_client(): region = 'us-east-1' service = 'es' credentials = boto3.Session().get_credentials() awsauth = AWS4Auth( credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token ) """Get OpenSearch client.""" return OpenSearch( [config.OPENSEARCH_HOST], use_ssl=config.OPENSEARCH_USE_SSL, port=config.OPENSEARCH_PORT, timeout=config.OPENSEARCH_TIMEOUT, max_retries=config.OPENSEARCH_MAX_RETRIES, retry_on_timeout=True, http_auth=awsauth, connection_class=RequestsHttpConnectionOpenSearch )