"""Track Validator. Contains the business logic around track operations such as uniqueness of ISRC, track ordering, etc. """ from oto import response from ows_product_physical.constant import error from ows_product_physical.constant import validation def _isrcs_are_unique_across_tracks(tracks): isrcs = [track.get('isrc') for track in tracks if track.get('isrc')] unique_isrcs = set(isrcs) return len(isrcs) == len(unique_isrcs) def _tracks_have_unique_track_numbers(tracks): track_numbers = [track.get('track_number') for track in tracks] unique_track_numbers = set(track_numbers) return len(track_numbers) == len(unique_track_numbers) def _tracks_go_from_one_to_number_of_tracks(tracks): track_numbers = sorted([track.get('track_number') for track in tracks]) return track_numbers == list(range(1, len(tracks) + 1)) def _disc_sequenced(discs): return max(discs) == len(discs) def _track_uniqueness_error(): return response.create_error_response( code=error.VALIDATION_ERROR, message=validation.TRACKS_UNIQUE_MSG, status=400) def _track_out_of_order_error(): return response.create_error_response( code=error.VALIDATION_ERROR, message=validation.SEQUENCE_INTEGRITY_MSG, status=400) def _disc_out_of_order_error(): return response.create_error_response( code=error.VALIDATION_ERROR, message=validation.SEQUENCE_DISC_INTEGRITY_MSG, status=400) def _isrc_uniqueness_error(): return response.create_error_response( code=error.VALIDATION_ERROR, message=validation.ISRC_UNIQUE_MSG, status=400) def validate_database_state(tracks): """Validate the state of tracks in the persistance layer. Args: tracks (list): A list of tracks for a single product or UPC. Returns: Response: the response of the validation operation. """ if not _isrcs_are_unique_across_tracks(tracks): return _isrc_uniqueness_error() discs = set([track.get('disc') for track in tracks]) sides = set([track.get('side') for track in tracks]) if discs and not _disc_sequenced(discs): return _disc_out_of_order_error() for disc in discs: disc_tracks = [track for track in tracks if track.get('disc') == disc] for side in sides: disc_side_tracks = \ [track for track in disc_tracks if track.get('side') == side] if not _tracks_have_unique_track_numbers(disc_side_tracks): return _track_uniqueness_error() if not _tracks_go_from_one_to_number_of_tracks(disc_side_tracks): return _track_out_of_order_error() return response.Response(message={'status': 'ok'}, status=200)