from typing import List, Optional from external_api.base.clients.client_factory import ApiClientFactory from external_api.base.clients.delphi_client import DelphiClient, AdsPerformanceQuery, AdPerformanceSummaryItem from performance.schemas import PerformanceMetricsParamsSchema, PerformanceMetricsListResponseSchema from performance.services.metrics_api.dimensions import Dimensions from performance.services.metrics_api.metrics_mapper import MetricsMapper from utils.list_utils import get_nested_attr from performance.services.metrics_api.metadata_providers import ( MetadataProvider, CampaignMetadataProvider, ProjectMetadataProvider, ) from performance.services.utils_service import UtilsService from performance.repository import MetricsApiSearchRepository from performance.services.metrics_api import utils from services.territory.territories_service import TerritoriesService class MetricsApiService: utils_service = UtilsService() territories_service: TerritoriesService = TerritoriesService() delphi_client: DelphiClient = ApiClientFactory.delphi_client() mapper: MetricsMapper = MetricsMapper() search_repo: MetricsApiSearchRepository = MetricsApiSearchRepository() async def get_campaigns_metrics(self, user_id: int, params: PerformanceMetricsParamsSchema): dimension = Dimensions.CAMPAIGN query = utils.build_performance_query(dimension, user_id, params) query.country_code = self.territories_service.get_country_code_for_delphi_api(params.territoryId) if params.freeText: campaign_ids = await self.search_repo.search_by_campaigns(params) if not campaign_ids: return PerformanceMetricsListResponseSchema(items=[]) query.campaign_id = campaign_ids query.is_assigned = True query.is_pending = None return await self.__get_metrics(dimension, query, CampaignMetadataProvider()) async def get_unassigned_campaigns_metrics(self, user_id: int, params: PerformanceMetricsParamsSchema): dimension = Dimensions.CAMPAIGN query = utils.build_performance_query(dimension, user_id, params) query.country_code = self.territories_service.get_country_code_for_delphi_api(params.territoryId) if params.freeText: campaign_ids = await self.search_repo.search_by_unassigned_campaigns(params) if not campaign_ids: return PerformanceMetricsListResponseSchema(items=[]) query.campaign_id = campaign_ids query.is_assigned = False query.is_pending = False return await self.__get_metrics(dimension, query, CampaignMetadataProvider()) async def get_projects_metrics(self, user_id: int, params: PerformanceMetricsParamsSchema): dimension = Dimensions.PROJECT query = utils.build_performance_query(dimension, user_id, params) query.country_code = self.territories_service.get_country_code_for_delphi_api(params.territoryId) if params.freeText: project_ids = await self.search_repo.search_by_projects(params) if not project_ids: return PerformanceMetricsListResponseSchema(items=[]) query.project_id = project_ids query.is_assigned = True query.is_pending = False return await self.__get_metrics(dimension, query, ProjectMetadataProvider()) async def get_artists_metrics(self, user_id: int, params: PerformanceMetricsParamsSchema): dimension = Dimensions.ARTIST query = utils.build_performance_query(dimension, user_id, params) query.country_code = self.territories_service.get_country_code_for_delphi_api(params.territoryId) query.is_assigned = True query.is_pending = False return await self.__get_metrics(dimension, query) async def __get_metrics( self, dimension: Dimensions, query: AdsPerformanceQuery, metadata_provider: Optional[MetadataProvider] = None ): metrics = await self.delphi_client.get_ads_performance(query) # Get ID query.group_by = None totals = await self.delphi_client.get_ads_performance(query) ids = self.__get_dimensions_ids(dimension, metrics.items) metadata = {} if metadata_provider is not None and ids is not None: metadata = metadata_provider.get_metadata(ids) return self.mapper.map_metrics(dimension=dimension, metrics=metrics, totals=totals, metadata=metadata) def __get_dimensions_ids(self, dimension: Dimensions, items: List[AdPerformanceSummaryItem]): path = dimension.dimension_entity_id_path() if path is None: return None return list(filter(None, map(lambda x: get_nested_attr(x.dimensions, path, None), items)))