"""Logic for Track Publishing Obligation.""" from backend.constants import api as api_constants from backend.constants import error from backend.constants import track_field as tf from backend.constants import us_publishing_obligation as pub_obl from backend.models import ows_contracts 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.utils.validation import format_missing_error @logic_util.verify_product_ownership def get_all_for_product( product_id, account_type, account_id): """Update publishing obligation data for specified tracks. 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 """ tracks_response = TrackPersister.get_all_by_product_id(product_id) if not tracks_response: return tracks_response return logic_util.make_publishing_obligation_response( tracks_response.message[api_constants.ITEMS]) @logic_util.verify_product_ownership def update( product_id, request_data, account_type, account_id): """Update publishing obligation data for specified tracks. Args: product_id (int): product id. request_data (list): List of answers for various tuids 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 """ vendor_is_mech_admin = bool( ows_contracts.is_mech_admin(account_type, account_id)) # Validate data for data in request_data: if not _is_valid_publishing_obligation_answers( data, vendor_is_mech_admin): return api_utils.create_validation_error_response( 'Invalid response for tuid {}', data[tf.TUID]) # Set third_party_publisher field to default database value if not set for data in request_data: data[tf.THIRD_PARTY_PUBLISHER] = \ data.get(tf.THIRD_PARTY_PUBLISHER) or 'N' # Pop publishers field while update for data in request_data: if tf.PUBLISHERS in data: del data[tf.PUBLISHERS] result = TrackPersister.update_multiple_tracks( request_data, belongs_to_product_id=product_id) if not result: return result return logic_util.make_publishing_obligation_response( result.message[api_constants.ITEMS]) @logic_util.verify_product_ownership def validate_for_product( product_id, account_type, account_id): """Validate the publishing obligation 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 """ tracks_response = TrackPersister.get_all_by_product_id(product_id) if not tracks_response: return tracks_response vendor_is_mech_admin = bool( ows_contracts.is_mech_admin(account_type, account_id)) # Validate publishing obligation for each track errors = [] for track in tracks_response.message['items']: error_obj = {} error_obj.update( _validate_publishing_obligation( track, vendor_is_mech_admin=vendor_is_mech_admin)) if error_obj: error_obj[tf.TUID] = track[tf.TUID] errors.append(error_obj) return api_utils.create_validation_response( tracks_response.message['items'], errors) def _is_valid_publishing_obligation_answers(data, vendor_is_mech_admin): """Validate publishing obligation answers. Args: data (dict): Set of answers for tuid vendor_is_mech_admin (bool): Specifies vendor mech admin status Returns: bool: True if data is valid """ us_publishing_obligation = data[tf.US_PUBLISHING_OBLIGATION] third_party_publisher = data.get(tf.THIRD_PARTY_PUBLISHER) or None publishers = data.get(tf.PUBLISHER_NAMES) or [] has_publishers = len(publishers) > 0 # Check if US Publishing Obligation can have 3rd-party publishers if us_publishing_obligation is None or \ us_publishing_obligation in pub_obl.NO_3RD_PARTY_ENUM: # Third party publisher can't be set to 'Y' and publishers cannot # be specified return third_party_publisher in (None, 'N',) # Make sure valid value for publishing obligation is specified if us_publishing_obligation not in pub_obl.OBLIGATION_ENUM: return False # US Publishing Obligation is set to Composition at this point if third_party_publisher == 'Y': # Vendor must have mech admin access to answer this question and must # also specify the publishers return vendor_is_mech_admin and has_publishers if third_party_publisher == 'N': # Filling out publishers is optional return True # Vendors with mech admin access must specify an answer # for third_party_publisher. Otherwise blank answer is allowed return not vendor_is_mech_admin def _validate_publishing_obligation(track, vendor_is_mech_admin): """Validate publishing obligation state in track. Note this differs from the `_is_valid_publishing_obligation_answers` since in this function the track data is being validated. The other function is concerned with making sure the answer set is valid, so it does more strict validation. Args: track (dict): Track dictionary vendor_is_mech_admin (bool): Specifies vendor mech admin status Return: dict: Dictionary of field errors """ us_publishing_obligation = track[tf.US_PUBLISHING_OBLIGATION] error_obj = {} if us_publishing_obligation not in pub_obl.OBLIGATION_ENUM: error_obj[tf.US_PUBLISHING_OBLIGATION] = format_missing_error( field_name=tf.US_PUBLISHING_OBLIGATION, error_code=error.MISSING_US_PUBLISHING_OBLIGATION ) return error_obj if us_publishing_obligation in pub_obl.NO_3RD_PARTY_ENUM: return error_obj # When not Mech Admin, vendor is not required to fill in additional fields if not vendor_is_mech_admin: return error_obj # At this point, third_party_publisher must have a valid value third_party_publisher = track[tf.THIRD_PARTY_PUBLISHER] if third_party_publisher not in ('Y', 'N',): error_obj[tf.THIRD_PARTY_PUBLISHER] = format_missing_error( field_name=tf.THIRD_PARTY_PUBLISHER, error_code=error.MISSING_THIRD_PARTY_PUBLISHER ) return error_obj if third_party_publisher == 'Y': # Track publishers are required if not track[tf.PUBLISHERS]: error_obj[tf.PUBLISHER_NAMES] = format_missing_error( field_name=tf.PUBLISHER_NAMES, error_code=error.MISSING_PUBLISHER_NAMES ) return error_obj