"""create-tracks.""" import uuid import config from config import graphql_gateway from constants import queries from ddex_ingester_common.constants.ddex_providers import SME from ddex_ingester_common.helpers.s3_ddex import ( get_s3_track, load_ddex_json ) from ddex_ingester_common.lambda_exceptions import CreateTracksException from ddex_ingester_common.logging import utils as logging_utils from ddex_ingester_common.schemas.s3_schema import S3Schema from ddex_ingester_common.schemas.state_machine_schema import ( StateMachineSchema ) from lambdacommon.graphql import graphql logger = logging_utils.get_logger(config.app_logger) def handler(event, context): """Lambda entry point.""" parsed_ddex = S3Schema().load(load_ddex_json(event)) context = StateMachineSchema().load(event) correlation_id = context.correlation_id or str(uuid.uuid4()) context.correlation_id = correlation_id logging_utils.update_logger_correlation_id(logger, correlation_id) logging_utils.update_logger_with_message_ids( logger, parsed_ddex.message_id, parsed_ddex.message_thread_id, parsed_ddex.execution_name ) graphql_gateway.set_headers( { 'Orchard-User-Id': config.OA_USER, 'Correlation-Id': correlation_id, } ) try: orchard_tracks = get_orchard_tracks(context.product.upc) product_id = context.product.product_id existing_tuids = [] tracks_to_create = [] tuids_to_delete = [] for context_track in context.tracks: if not context_track.tuid: s3_track = get_s3_track(parsed_ddex, context_track) tracks_to_create.append(s3_track) else: existing_tuids.append(context_track.tuid) for orchard_track in orchard_tracks: orchard_track_tuid = int(orchard_track['tuid']) if orchard_track_tuid not in existing_tuids: tuids_to_delete.append(orchard_track_tuid) if not context.artwork_ingestion_only: delete_tracks(product_id, tuids_to_delete) created_tracks = create_tracks(product_id, tracks_to_create) enrich_track_tuids(context, created_tracks) update_track_sequence_numbers(context, parsed_ddex) except graphql.GraphQLError as err: if context.ddex_provider == SME: raise CreateTracksException('Graphql error') from err raise except Exception as exp: if context.ddex_provider == SME: raise CreateTracksException(f'Error creating tracks.\n{exp}') \ from exp raise return StateMachineSchema().dump(context) def get_orchard_tracks(upc): """Retrieve existing tracks in the orchard for a certain UPC. Args: upc (string): Product UPC Returns: list """ result = graphql_gateway.execute( queries.get_orchard_tracks, {'upc': upc} ) logger.info(f'Tracks found for UPC {upc}: {result}') if result['data']['productByUpc']: return result['data']['productByUpc']['tracks'] else: return [] def delete_tracks(product_id, tuids): """Delete tracks with tuids in the list. Args: product_id (string): Product ID tuids (list): Tuids of tracks to delete """ if not product_id or not tuids: logger.info('Skipped deleting tracks') return payload = { 'delete': { 'productId': product_id, 'tracks': tuids } } graphql_gateway.execute( queries.save_tracks, {'data': payload} ) logger.info( f'Deleted tracks with payload {payload}') def create_tracks(product_id, tracks): """Create the tracks in the list. Args: product_id (string): Product ID tracks (list): List of S3 Tracks to create Returns: list """ if not product_id or not tracks: logger.info('Skipped creating tracks') return tracks_payload = [] for track in tracks: tracks_payload.append({ 'isrc': track.isrc, 'trackName': track.track_name, 'volumeNumber': track.volume, 'explicit': track.explicit }) payload = { 'create': { 'productId': product_id, 'tracks': tracks_payload } } logger.info(f'Creating tracks with payload {payload}') result = graphql_gateway.execute( queries.save_tracks, {'data': payload} ) return result['data']['saveTracks'] def enrich_track_tuids(context, new_tracks): """Populate context with tuids of created tracks. Args: context (object): Context object new_tracks (list): List that was returned when creating the tracks """ if not new_tracks: logger.info('Skipped populating track tuids') return for new_track in new_tracks: context_track = next( ( context_track for context_track in context.tracks if context_track.isrc == new_track['isrc'] ), None) context_track.tuid = int(new_track['tuid']) def update_track_sequence_numbers(context, parsed_ddex): """Update sequence number of tracks. Args: context (object): Context object parsed_ddex (object): S3 DDEX object """ tracks_payload = [] for context_track in context.tracks: s3_track = get_s3_track(parsed_ddex, context_track) tracks_payload.append({ 'trackNumber': s3_track.sequence_number, 'volumeNumber': s3_track.volume, 'tuid': context_track.tuid }) payload = { 'updatePosition': { 'productId': context.product.product_id, 'tracks': tracks_payload } } logger.info( f'Updating track sequence numbers with payload {payload}' ) graphql_gateway.execute( queries.save_tracks, {'data': payload} )