"""Module that contains product-level asset operations.""" import json from typing import Any from sqlalchemy.exc import SQLAlchemyError from assets.constants import ( api, asset_types as asset_types_const, error, product as product_constants, ) from assets.constants.asset_status import ( STATUS_VALIDATION_ERROR, STATUS_VALIDATION_WARNING, ) from assets.exceptions import ( AssetFinalNotFound, InvalidProductStatus, ) from assets.logic import delete as delete_logic from assets.models import ( asset_final, asset_status as asset_status_model, asset_upload, asset_upload_type, ows_product, ows_track, ) def _get_validation_status_info(asset_status_description: str) -> dict[str, Any]: try: status_description = json.loads(asset_status_description) except json.decoder.JSONDecodeError: return {} metadata = status_description.get("metadata") errors = status_description.get("errors") or {} warnings = status_description.get("warnings") or {} if not metadata or not (errors or warnings): return {} return { "metadata": metadata, "invalid_metadata": list(errors), "warning_metadata": list(warnings), } def get_assets_by_product_id(product_id: int) -> dict[str, Any]: """Return assets info for product. Args: product_id (int): Product id. Returns: dict: assets info """ assets_data = asset_upload.get_asset_uploads_by_product_id( product_id, api_version=api.API_VERSION_V2 ) if not assets_data: return {"product_id": product_id, "upc": None, "assets": []} upc = int(next(asset["upc"] for asset in assets_data if asset["upc"])) asset_upload_ids = [asset["id"] for asset in assets_data] asset_statuses = asset_status_model.get_asset_statuses_by_asset_upload_ids( asset_upload_ids ) assets_result = [] for asset in assets_data: asset_status = asset_statuses[asset["id"]] status = asset_status["status"] if asset_status else None try: asset_final_response = ( asset_final.get_asset_final_by_asset_upload_id_and_type( asset["id"], asset_types_const.TYPE_FILE_MP3_192 ) ) except (AssetFinalNotFound, SQLAlchemyError): asset_final_response = None asset["stream"] = {} if asset_final_response: # The url key in stream is found by the UI in a separate flow asset["stream"] = { "track_unique_id": asset["track_unique_id"], "duration": int(asset_final_response.get("duration", 0)) / 1000, } asset_result = { "track_unique_id": asset["track_unique_id"], "asset_upload_type": asset_upload_type.resolve_asset_upload_type( asset["asset_upload_type_id"] ), "filename": asset["filename"], "original_filename": asset["original_filename"], "status": status, "stream": asset["stream"], } if status in (STATUS_VALIDATION_ERROR, STATUS_VALIDATION_WARNING): asset_result = { **asset_result, **_get_validation_status_info(asset_status["message"]["description"]), } assets_result.append(asset_result) return {"product_id": product_id, "upc": upc, "assets": assets_result} def get_asset_final_items_with_asset_upload_by_product_id_v2( product_id: int, asset_final_asset_types_filter: set[str], ) -> list[dict[str, Any]]: """Return asset_final items with their asset_upload for all tracks of product. Args: product_id (int): Product id. asset_final_asset_types_filter (set): Set of asset types to filter by. Returns: list: A list of asset_final items with their asset_upload. """ tracks_result = ows_track.get_tracks_by_product_id(product_id) tracks = tracks_result["items"] if not tracks: return [] track_ids = [track["tuid"] for track in tracks] asset_upload_response = asset_upload.get_asset_uploads_by_product_id( product_id, api_version=api.API_VERSION_V2 ) asset_upload_items = [ asset_upload_item for asset_upload_item in asset_upload_response if asset_upload_item["track_unique_id"] in track_ids ] asset_final_items = asset_final.get_asset_final_by_asset_upload_ids( [asset_upload_item["id"] for asset_upload_item in asset_upload_items] ) asset_final_items_with_asset_upload = [ {**asset_final_item, "asset_upload": asset_upload_item} for asset_upload_item in asset_upload_items for asset_final_item in asset_final_items[asset_upload_item["id"]] if ( not asset_final_asset_types_filter or asset_final_item["asset_type"] in asset_final_asset_types_filter ) ] return asset_final_items_with_asset_upload def remove_image_assets_by_product_id(product_id: int) -> dict[str, Any]: """Remove image assets by product id, v2. Delete image belonging to product with product_id. Args: product_id (int): id of product. Returns: dict: Response object with success or error message. """ ows_product_details = ows_product.get_product_by_id(product_id) product_status = ows_product_details["status"] if product_status == product_constants.PRODUCT_STATUS_IN_CONTENT: raise InvalidProductStatus(error.ERROR_MESSAGE_PRODUCT_IN_CONTENT) product_images_response = asset_upload.get_asset_uploads( product_id=product_id, track_id=0, api_version=api.API_VERSION_V2, ) return delete_logic.delete_assets(product_images_response) def get_assets_info_by_product_ids( product_ids: list[int], asset_types: list[str] ) -> list[dict[str, Any]]: """Get S3 assets detail for products. Args: product_ids: (list[int]): Product IDs. asset_types: (list[str]): Asset types to include. Returns: list: S3 assets. """ return _format_asset_response( asset_final.get_product_asset(product_ids, asset_types) ) def get_assets_info_by_product_id(product_id: int) -> list[dict[str, Any]]: """Get S3 assets detail for a product. Args: product_id: (int): Product ID. Returns: list: S3 assets. """ s3_assets = [] try: assets_finals_response = asset_final.get_product_asset([product_id]) s3_assets.extend(assets_finals_response) except AssetFinalNotFound: pass return _format_asset_response(s3_assets) def _format_asset_response(s3_assets: list[dict[str, Any]]) -> list[dict[str, Any]]: return [ { "tuid": asset.get("tuid") or asset.get("track_unique_id"), "product_id": asset.get("product_id"), "asset_type": asset.get("asset_type"), "s3_bucket": asset.get("s3_bucket"), "s3_key": asset.get("s3_key"), "updated_timestamp": asset.get("updated_timestamp") or asset.get("last_updated"), "updated_timestamp_us_east": asset.get("updated_timestamp_us_east") or asset.get("last_updated_us_east"), "duration": asset.get("duration"), "duration_ms": asset.get("duration_ms"), } for asset in s3_assets ]