"""Logic for retrieving product metadata.""" from typing import Any, Mapping from ddtrace import tracer from oto import response from analytics.connectors import dynamo from analytics.constants import cache from analytics.schemas.product_metadata import ProductMetadataSchema from analytics.utils.cache import cache_in_redis TRACK_NAME = "track_name" TRACK_NUMBER = "track_number" TRACK_CD = "track_cd" TRACK_TYPE = "track_type" ISRC = "isrc" def _to_dynamo_permissions_filter(permissions: Mapping[str, Any]) -> dict: return { "artist_ids": permissions.get("permission_artist_ids"), "subaccount_ids": permissions.get("permission_subaccount_ids"), "label_ids": permissions.get("permission_label_ids"), } def _clean_values(item): """Replace invalid null chars as None.""" for key, value in item.items(): if value == r"\N": item[key] = None return item def _add_fallback_artists_list(sound_recording, product): """Use the product's artist list when the track's artist list is empty.""" if not sound_recording.get("artists"): sound_recording["artists"] = product["artists"] return sound_recording def _get_track_metadata(product, items): """Generate metadata for tracks on product.""" tracks = [ { TRACK_NAME: item.get(TRACK_NAME), ISRC: item.get(ISRC), TRACK_NUMBER: item.get(TRACK_NUMBER), TRACK_CD: item.get(TRACK_CD), TRACK_TYPE: item.get(TRACK_TYPE), **_clean_values(_add_fallback_artists_list(item, product)), } for item in items if item != product ] tracks.sort(key=lambda x: x[TRACK_NUMBER]) return tracks @tracer.wrap(name="get_product_metadata") @cache_in_redis(ttl=cache.ONE_HOUR) def get_product_metadata( query_params: Mapping[str, Any], permissions: Mapping[str, Any] ): """Return product metadata for the given product_id.""" product_id = query_params["product_id"] permissions_filter = _to_dynamo_permissions_filter(permissions) key = dynamo.create_product_key(product_id) items = dynamo.query_by_hash_key(key, permissions_filter=permissions_filter) if not items: return response.create_not_found_response() product = next((x for x in items if x[dynamo.RANGE_KEY] == key), None) if not product: return response.create_not_found_response() product["artists"] = [ {"artist_name": product.get("artist_name", ""), "type": "performer"} ] _clean_values(product).update( { "product_id": product_id, "label_id": product["label_id"], "subaccount_id": product.get("subaccount_id"), "tracks": _get_track_metadata(product, items), } ) view_model = ProductMetadataSchema.normalize(product, permissions_filter) return response.Response(view_model)