"""Performer-related logic.""" from collections import defaultdict from oto import response from backend.constants import error from backend.constants import performer as pfmr_const from backend.constants import track_field as tf from backend.models.performer_persister import PerformerPersister from backend.models.track_persister import TrackPersister from backend.utils import api as api_utils from backend.utils import logic as logic_util from backend.validation import performer_validators def get_performer_roles(): """Get performer roles from DB. Returns: response.Response: list of performer roles """ return PerformerPersister.get_performer_roles() @logic_util.verify_product_ownership def get_for_track(tuid, account_type, account_id): """Get performers data for track with tuid. Args: tuid (int): Primary key of track account_type (str): the user account type in the header. account_id (int): the user account id in the header. Returns: Response: dict with tuids and performer data """ res = PerformerPersister.get_performers_by_tuid(tuid) return _make_get_by_tuid_response(tuid, res) def get_for_tracks(tuids): """Get performers data for track ids. Args: tuids (list): List of track ids. Returns: Response: dict with tuids and performer data. """ res = PerformerPersister.get_performers_by_tuids(tuids) return _make_get_by_product_id_response(tuids, res) @logic_util.verify_product_ownership def get_all_for_product(product_id, account_type, account_id): """Get performers data for tuids in given product_id. Args: product_id (int): Primary key of product account_type (str): the user account type in the header. account_id (int): the user account id in the header. Returns: Response: dict with tuids and performer data """ all_tracks = TrackPersister.get_all_by_product_id(product_id) tuids = [track['tuid'] for track in all_tracks.message['items']] performers_response = PerformerPersister.get_performers_by_tuids(tuids) return _make_get_by_product_id_response(tuids, performers_response) @logic_util.verify_product_ownership def update_for_track(tuid, performers, account_type, account_id): """Update performers with roles to given tuid. Args: tuid (int): Primary key of track performers (list): List of performers to update track with account_type (str): the user account type in the header account_id (int): the user account id in the header Returns: Response: dict with tuid and created performer roles """ res = PerformerPersister.sync_track_performers(tuid, performers) return _make_get_by_tuid_response(tuid, res) @logic_util.verify_product_ownership def update_by_performer_type_for_product( product_id, performer_type, performers, account_type, account_id): """Update all product tracks so performer data is the same for that type. Args: product_id (int): Primary key of product performer_type (str): Performer type to update performers (list): List of performers to update track with account_type (str): the user account type in the header account_id (int): the user account id in the header Returns: Response: dict with tuid and created performer roles """ # TODO: Verify all information is complete if performer_type not in pfmr_const.PERFORMER_TYPES: return response.create_error_response( code=error.INVALID_CODE, message='Invalid performer type') error_obj = \ performer_validators.validate_performers_birth_name(performers) if error_obj: return response.create_error_response( code=error_obj['performers']['validator'], message=error_obj['performers']['message']) all_tracks = TrackPersister.get_all_by_product_id(product_id) tuids = [track['tuid'] for track in all_tracks.message['items']] res = PerformerPersister.sync_by_performer_type_for_tracks( tuids, performer_type, performers) if not res: return res # Return all the performers performers_response = PerformerPersister.get_performers_by_tuids(tuids) return _make_get_by_product_id_response(tuids, performers_response) @logic_util.verify_product_ownership def validate_for_product(product_id, account_type, account_id): """Validate the performer data for all tracks of a product. Returns the total number of tracks and the number of valid ones. Args: product_id (int): product id. account_type (string): the user account type in the header. account_id (int): the user account id from the header. Returns: response.Response: a Response object with JSON data """ performers_response = get_all_for_product( product_id=product_id, account_type=None, account_id=None) if not performers_response: return performers_response # Validate performers for each track errors = [] for track_performers in performers_response.message['items']: error_obj = performer_validators.validate_performers_complete( track_performers[tf.TUID], track_performers[pfmr_const.PERFORMERS]) if error_obj: errors.append(error_obj) return api_utils.create_validation_response( performers_response.message['items'], errors) @logic_util.verify_product_ownership def delete_performers_by_tuid(tuid, account_type, account_id): """Delete performers with given tuid. Args: tuid (int): unique id of track account_type (str): the user account type in the header account_id (int): the user account id in the header Returns: response.Response: result of deletion """ return bulk_delete_performers_by_tuids([tuid]) @logic_util.verify_product_ownership def bulk_delete_performers_by_tuids(tuids, account_type, account_id): """Delete performers with given tuids. Args: tuids (list): unique ids of tracks account_type (str): the user account type in the header account_id (int): the user account id in the header Returns: response.Response: result of deletion """ return PerformerPersister.bulk_delete_performers_by_tuids(tuids) def _make_get_by_tuid_response(tuid, performer_response): """Make logical response using persister response data. Args: tuid (int): Primary key of track performer_response (Response): Persister response """ if not performer_response: return performer_response sorted_performers = _sort_performers(performer_response.message['items']) performers_output = [] for performer in sorted_performers: p = performer.copy() del p[tf.TUID] performers_output.append(p) return response.Response({ tf.TUID: tuid, pfmr_const.PERFORMERS: performers_output}) def _make_get_by_product_id_response(tuids, performers_response): """Group performers information by tuids. Args: tuids (list): list of tuids performers_response (Response): response object with performers data Returns: response: Response with performers data """ sorted_performers = _sort_performers(performers_response.message['items']) grouped_performers = defaultdict(list) for performer in sorted_performers: p = performer.copy() del p['tuid'] grouped_performers[performer['tuid']].append(p) tracks_performers = [] for tuid in tuids: tracks_performers.append({ 'tuid': tuid, 'performers': grouped_performers.get(tuid, []) }) return api_utils.create_get_list_response(tracks_performers) def _sort_performers(performers): """Sort performer list in same order as PERFORMER_TYPES. This will make it so primary performers appear before featured, and featured appear before non-featured Args: performers (list): List of performer dictionaries Returns: list: Performers sorted by PERFORMER_TYPES """ performers_by_type = defaultdict(list) for performer in performers: performer_type = performer['type'] performers_by_type[performer_type].append(performer) results = [] for performer_type in pfmr_const.PERFORMER_TYPES: results += performers_by_type[performer_type] return results