from datetime import date from typing import Optional, List from flask import g from external_api.base.analytics_models import ArtistFollowersQuery, ProjectStreamsQuery from external_api.base.clients.client_factory import ApiClientFactory from external_api.base.clients.delphi_client import DelphiClient, AdsPerformanceQuery, AdsPerformanceResponse from reporting.services.reporting_metrics.combined_metrics import CombinedMetrics from reporting.services.reporting_metrics.combined_metrics_builder import CombinedMetricsBuilder from reporting.services.reporting_metrics.aggregators import agg_by_date from services.territory.constants import WORLDWIDE from utils.async_helpers import safe_gather, immediate_task from utils.list_utils import flattern from models import StreamRate from reporting.schemas import ReportingType class CombinedMetricsFetcher: delphi_client: DelphiClient = ApiClientFactory.delphi_client() def is_in_type(self, reporting_type, r_type): return reporting_type == r_type or reporting_type == ReportingType.ALL_METRICS.value async def fetch_metrics( self, start_date: date, end_date: date, country_code: str, artists_ids: List[str], campaigns_ids: List[str], project_id: Optional[str], dsps: List[str], project_gras_code: Optional[str], revenue_stream_rate: Optional[StreamRate] = None, reporting_type: Optional[int] = None, ) -> List[CombinedMetrics]: tasks = [] if self.is_in_type(reporting_type, ReportingType.STREAMS.value): tasks.append(self.__get_streams( project_gras_code=project_gras_code, start_date=start_date, end_date=end_date, country_code=country_code, )) else: tasks.append(immediate_task(None)) if self.is_in_type(reporting_type, ReportingType.FOLLOWERS.value) and country_code is WORLDWIDE: tasks.append(self.__get_followers(artists_ids, start_date, end_date)) else: tasks.append(immediate_task(None)) if "facebook" in dsps and self.is_in_type(reporting_type, ReportingType.DSP_METRICS.value): tasks.append( self.__get_metrics( "facebook", campaigns_ids, project_id, start_date, end_date, country_code=country_code ) ) # [2] for facebook else: tasks.append(immediate_task(None)) if "google" in dsps and self.is_in_type(reporting_type, ReportingType.DSP_METRICS.value): tasks.append( self.__get_metrics("google", campaigns_ids, project_id, start_date, end_date, country_code=country_code) ) # [3] for google else: tasks.append(immediate_task(None)) if "linkfire" in dsps and self.is_in_type(reporting_type, ReportingType.DSP_METRICS.value): tasks.append( self.__get_metrics( "linkfire", campaigns_ids, project_id, start_date, end_date, country_code=country_code ) ) # [4] for linkfire else: tasks.append(immediate_task(None)) # Skip errors and try to build response anyway response = await safe_gather(tasks, []) builder = CombinedMetricsBuilder() builder.streams_data = response[0] builder.followers_data = response[1] builder.facebook_metrics = response[2] builder.google_metrics = response[3] builder.linkfire_metrics = response[4] return builder.build(start_date, end_date, revenue_stream_rate=revenue_stream_rate) async def __get_streams( self, project_gras_code, start_date: date, end_date: date, country_code: str, ): project_streams = self.delphi_client.get_project_streams_by_day( ProjectStreamsQuery( start_date=start_date.isoformat(), end_date=end_date.isoformat(), project_number=project_gras_code, country_code=country_code, ) ) return agg_by_date(await project_streams) async def __get_followers(self, artists_ids: List[str], start_date: date, end_date: date): if not artists_ids: return [] return agg_by_date( flattern( await safe_gather( [ self.delphi_client.get_artist_followers( ArtistFollowersQuery( artist_id=artist_id, start_date=start_date.isoformat(), end_date=end_date.isoformat() ) ) for artist_id in artists_ids if artist_id is not None ], [], ) ) ) async def __get_metrics( self, dsp: str, campaigns_ids: List[str], project_id: str, start_date: date, end_date: date, country_code: str = None, ) -> Optional[AdsPerformanceResponse]: if country_code == WORLDWIDE: country_code = None params = AdsPerformanceQuery( start_date=start_date, end_date=end_date, user_id=g.user_id, # TODO: Pass user_id through function parameters group_by=["date"], dsp=[dsp], is_pending=False, is_assigned=True, country_code=country_code, ) if not project_id and not campaigns_ids: return None if not campaigns_ids: params.project_id = project_id else: params.campaign_id = campaigns_ids try: return await self.delphi_client.get_ads_performance(params) except Exception: return None