"""Handler for TRACK:METADATA_UPDATE.""" from switchboard_consumer.connectors.sentry import sentry_client from switchboard_consumer.constants.exceptions import ( GraphQLError, ParticipantHandlerError, ParticipantHandlerGraphQLError ) from switchboard_consumer.constants.release_type import VIDEO_SINGLE from switchboard_consumer.constants.system import SONY from switchboard_consumer.formatters.errors import ( format_exception, format_generic_error, format_graphql_errors ) from switchboard_consumer.formatters.product import ( get_company_code ) from switchboard_consumer.formatters.track import \ format_switchboard_to_orchard_track, format_track_unmapped_publishers from switchboard_consumer.logic.\ label_participant.label_participant_handler import ( LabelParticipantHandler ) from switchboard_consumer.logic.participant.track_participant_handler \ import TrackParticipantHandler from switchboard_consumer.logic.performer.track_performer_handler \ import TrackPerformerHandler from switchboard_consumer.logic.preprocessing.product import ( preprocess as preprocess_product) from switchboard_consumer.logic.preprocessing.track import ( preprocess as preprocess_track ) from switchboard_consumer.logic.product import release_correct_product from switchboard_consumer.logic.release_correction.release_correction import ( needs_release_correcting ) from switchboard_consumer.logic.tracks import get_publisher_processing_results from switchboard_consumer.logic.validation.track import validate from switchboard_consumer.utils.graphql import is_error from switchboard_consumer.utils.message import ( create_processing_result, get_system_local_id) from switchboard_consumer.utils.product import \ construct_product_kafka_message def _format_update_orchard_tracks_payload( orchard_tuids, swb_track_body, artists, writers, performers, logger): return { 'tracks': orchard_tuids, 'body': format_switchboard_to_orchard_track( swb_track_body, artists, writers, performers, logger) } def handle_track_metadata_update( logger, message, swb_client, orchard_client): """Handler for track metadata updates.""" results = [] orchard_tuids = [] for orchard_local_id in message.orchard_local_ids: orchard_tuids.append(int(orchard_local_id['localId'])) logger.info('Found tracks to update: {}'.format(orchard_tuids)) if not orchard_tuids: logger.error('Did not find any tracks to update') return results swb_local_id = message.sending_system_local_id isrc = swb_local_id['businessKey'] swb_track_response = swb_client.lookup_track_by_isrc( isrc, message.correlation_id) if swb_track_response.get('errors'): errors = swb_track_response['errors'] logger.error( 'Problem getting track info from SWB. - {}'.format(errors)) results.append(create_processing_result( message.ids, message, errors=format_graphql_errors(errors))) return results preprocess_track(swb_track_response) processing_results = validate.validate_track(swb_track_response, message) if processing_results: results.append(processing_results) return results # There can be multiple Orchard mappings for a single Track... # We have to work out the Product associated with each mapping # and determine the Product status to check whether we update # through release correction try: (products_to_release_correct, tracks_to_update) = determine_track_update_method( orchard_tuids, orchard_client, swb_client, message, logger ) except GraphQLError as e: error_message = ('Failed to get Product status for Orchard TUIDs ' f'{orchard_tuids}') logger.error(error_message, custom_fields={ 'raw_error': e }) results.append(create_processing_result( message.ids, message, errors=[format_generic_error( error_message)])) return results orchard_tuids = tracks_to_update for product in products_to_release_correct: logger.info((f'Release correcting Product {product} associated ' f'with Tracks {message.orchard_local_ids}')) product_message = construct_product_kafka_message(product, message) product = preprocess_product(product) rc_results = release_correct_product( get_system_local_id(product)['localId'], product, product_message, swb_client, orchard_client, logger ) results.extend(rc_results) if list(filter(lambda result: result['errors'], rc_results)): # Errors processing release corrections # Construct processing result for track as well results.append(create_processing_result( message.ids, message, errors=[format_generic_error( ('Failed to update associated Product via release ' 'correction') )] )) return results if not orchard_tuids: results.append(create_processing_result(message.ids, message)) return results vendor_id = get_company_code(swb_track_response['labelAccount']) subaccount_id = get_company_code(swb_track_response['subAccount']) # We need to get the parent product of the track we are updating to be able # to grab the genre of the product do do genre specific logic # i.e specific track contributor role mappings for Classical genres orchard_track = orchard_client.get_track_by_tuid( orchard_tuids[0], correlation_id=message.correlation_id) if is_error(orchard_track): error_message = 'Error encountered getting Track info from The Orchard' logger.error(error_message, custom_fields={ 'raw_errors': orchard_track['errors'], 'track_id': orchard_tuids[0] }) results.append(create_processing_result( message.ids, message, errors=[format_generic_error( error_message)])) return results swb_product = swb_client.get_product_by_upc({ 'businessKey': orchard_track['upc'], 'system': SONY }, message.correlation_id) if is_error(swb_product): error_message = 'Error encountered getting Product info from SWB' logger.error(error_message, custom_fields={ 'raw_errors': swb_product['errors'], 'upc': orchard_track['upc'] }) results.append(create_processing_result( message.ids, message, errors=[format_generic_error( error_message)])) return results track_participant_handler = TrackParticipantHandler(swb_product, logger, orchard_client, message, vendor_id, subaccount_id) try: (processing_results, artists, writers) = track_participant_handler.process(swb_track_response) results.extend(processing_results) except ParticipantHandlerGraphQLError as e: if sentry_client: sentry_client.captureException() results.append(create_processing_result( message.ids, message, errors=e.raw_errors )) return results except ParticipantHandlerError as e: if sentry_client: sentry_client.captureException() results.append(create_processing_result( message.ids, message, exception=format_exception(e) )) return results track_performer_handler = TrackPerformerHandler(swb_track_response, logger) performers = track_performer_handler.process() update_tracks_payload = _format_update_orchard_tracks_payload( orchard_tuids, swb_track_response, artists, writers, performers, logger ) unmapped_publishers = { swb_track_response['isrc']: format_track_unmapped_publishers( swb_track_response)} logger.info( 'About to update_tracks for tracks {}'.format(orchard_tuids), custom_fields={ 'payload': update_tracks_payload }) update_tracks_response = orchard_client.update_tracks( update_tracks_payload, message.correlation_id) if isinstance(update_tracks_response, dict) and \ update_tracks_response.get('errors'): errors = update_tracks_response['errors'] logger.error('Problem updating tracks. - {}'.format(errors)) results.append(create_processing_result( message.ids, message, errors=format_graphql_errors(errors))) return results label_participant_handler = \ LabelParticipantHandler(orchard_client, vendor_id, subaccount_id, message.correlation_id, logger) for track in update_tracks_payload['tracks']: label_participants = \ label_participant_handler.create_label_participants( swb_track_response['contributors'] ) label_participant_handler.set_label_participants_for_track( swb_track_response['isrc'], label_participants ) logger.info('Successfully updated tracks') results.append(create_processing_result(message.ids, message)) results.extend(get_publisher_processing_results( logger, message, update_tracks_response, unmapped_publishers)) return results def determine_track_update_method(orchard_tuids, orchard_client, swb_client, message, logger): """determine_track_update_method Determine whether a track mapping needs to be updated via release corrections or through graphql update track endpoint. If the Product for a track is in a release correction state we have to release correct that Product. The track also may belong to a Product that is not in release corrections. """ products_to_release_correct = [] tracks_to_update = [] for tuid in orchard_tuids: logger.info(f'Determining track update method for Track {tuid}') orchard_track = orchard_client.get_track_by_tuid( tuid, correlation_id=message.correlation_id) if is_error(orchard_track): errors = orchard_track['errors'] logger.error('Problem getting track info from The Orchard', custom_fields={ 'raw_errors': errors, 'track_id': tuid }) raise GraphQLError('Problem getting track info from The Orchard', errors) # Get associated Switchboard Product swb_product = swb_client.get_product_by_upc({ 'businessKey': orchard_track['upc'], 'system': SONY }, message.correlation_id) if is_error(swb_product): errors = swb_product.get('errors') logger.error('Error getting product by upc from SWB', custom_fields={ 'raw_errors': errors, 'upc': orchard_track['upc'] }) raise GraphQLError('Error getting product by upc from SWB', errors) # Get Orchard Product details orchard_product = orchard_client.get_product_by_id( orchard_track['productId'], correlation_id=message.correlation_id) if is_error(orchard_product): errors = orchard_product['errors'] logger.error('Problem getting Product info from The Orchard', custom_fields={ 'raw_errors': errors, 'product_id': orchard_track['productId'] }) raise GraphQLError('Problem getting Product info from The Orchard', errors) # Determine Product state product_display_status = orchard_product['displayStatus'] is_video_product = swb_product['releaseType'] == VIDEO_SINGLE is_release_correctable = needs_release_correcting( product_display_status, orchard_product.get( 'releaseCorrectionId') ) if (is_release_correctable and is_video_product): logger.info((f'Product for Track {tuid} is a video Product ' 'in complete state which does not support ' 'updating via release correction')) elif (is_release_correctable): logger.info(f'Product for Track {tuid} needs release correcting.') products_to_release_correct.append(swb_product) else: logger.info(f'Track {tuid} to be updated.') tracks_to_update.append(tuid) return products_to_release_correct, tracks_to_update