import decimal from dataclasses import dataclass from typing import Any from anydi import singleton from fansifter_common.auth.types import Permission from pydantic import TypeAdapter from dmp.adapters.db import ReportingDB from dmp.artists.cache import ArtistCache, cached_artist_data from dmp.artists.dtos import FansShareByHeavyRotation from dmp.artists.requests import ArtistFanReportFilterRequest from dmp.artists.services import ArtistAccessService from dmp.fandata.enums import HeavyRotation @dataclass class GetArtistFansShareByHeavyRotationRequest(ArtistFanReportFilterRequest): countries: list[str] | None @dataclass class GetArtistFansShareByHeavyRotationResponse: available_fans_share: decimal.Decimal items: list[FansShareByHeavyRotation] HeavyRotationsFansShareListValidator = TypeAdapter(list[FansShareByHeavyRotation]) @singleton class GetArtistFansShareByHeavyRotationHandler: permission = Permission("fan_data_list", "view") def __init__( self, db: ReportingDB, artist_access_service: ArtistAccessService, artist_cache: ArtistCache, ) -> None: self.db = db self.artist_access_service = artist_access_service self.artist_cache = artist_cache def handle( self, request: GetArtistFansShareByHeavyRotationRequest ) -> GetArtistFansShareByHeavyRotationResponse: artist_access = self.artist_access_service.check_artist_access( request.identity_id, request.global_participant_id, request.account, permission=self.permission, ) available_fans_share = self._get_available_fans_share( request.global_participant_id, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, countries=request.countries, is_global=artist_access.is_global, ) heavy_rotations = self._get_heavy_rotations( request.global_participant_id, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, countries=request.countries, is_global=artist_access.is_global, ) return GetArtistFansShareByHeavyRotationResponse( available_fans_share=available_fans_share, items=heavy_rotations, ) @cached_artist_data("heavy-rotation-available-fans-share") def _get_available_fans_share( self, global_participant_id: str, vendor_id: int | None, subaccount_id: int | None, countries: list[str] | None, is_global: bool, ) -> decimal.Decimal: context = self._get_query_context( vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, countries=countries, is_global=is_global, ) if countries: template_name = ( "artist/get-artist-heavy-rotation-available-fans-share-by-country.sql" ) else: template_name = "artist/get-artist-heavy-rotation-available-fans-share.sql" query = self.db.query_from_template(template_name, context=context) return decimal.Decimal(self.db.session.execute(query).scalar_one_or_none() or 0) @cached_artist_data("fans-share-by-heavy-rotation") def _get_heavy_rotations( self, global_participant_id: str, vendor_id: int | None, subaccount_id: int | None, countries: list[str] | None, is_global: bool, ) -> list[FansShareByHeavyRotation]: context = self._get_query_context( vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, countries=countries, is_global=is_global, ) if countries: template_name = "artist/get-artist-fans-share-by-heavy-rotation-country.sql" else: template_name = "artist/get-artist-fans-share-by-heavy-rotation.sql" query = self.db.query_from_template(template_name, context=context) return HeavyRotationsFansShareListValidator.validate_python( self.db.session.execute(query).mappings() ) @staticmethod def _get_query_context( vendor_id: int | None, subaccount_id: int | None, global_participant_id: str, countries: list[str] | None, is_global: bool, ) -> dict[str, Any]: return { "vendor_id": vendor_id, "subaccount_id": subaccount_id, "global_participant_id": global_participant_id, "heavy_rotation_enum": HeavyRotation, "countries": countries, "is_global": is_global, }