from datetime import datetime, timedelta from typing import Optional import pytz from delphi_api.const import ENABLE_FAKE_DATA from delphi_api.errors import Codes, InvalidInputError from delphi_api.utils import DateUtils, Models from delphi_api.v3.constants import ( DUMMY_POPULARITY, DUMMY_POPULARITY_CHANGE, ) from delphi_api.v3.data_models.schemas.generics import PopularitySchema from delphi_api.v3.view_models.artist import ArtistsViewModel from delphi_api.v3.view_models.fake_utils import FakeUtils from delphi_api.v3.view_models.params import Params from delphi_api.v3.view_models.query_builder import QueryBuilder class PopularityViewModel: @staticmethod def _get_fake_popularity(params: Params) -> dict: return FakeUtils.get_fake_temporal_data(params, 'spotify_popularity', count=DUMMY_POPULARITY, change_amount=DUMMY_POPULARITY_CHANGE, count_max=100) @classmethod def get_many(cls, params: dict): params = Params(**params) if ENABLE_FAKE_DATA: result = cls._get_fake_popularity(params) else: result = cls.get_popularity_data(params) result = QueryBuilder.sort_results(result, params) result = QueryBuilder.limit_offset_results(result, params) return PopularitySchema(many=True).dump(result) @classmethod def get_popularity_data(cls, params: Params): base_key = 'artist_id' followers = ArtistsViewModel.get_followers_data(params) items = PopularitySchema(many=True).dump(followers) grouped_data = Models.aggregate_generic(items, base_key, group_by=params.group_by) return Models.flatten_generic(grouped_data) @classmethod def get_latest_artist_popularity(cls, artist_id: str) -> Optional[int]: """Get the most recent artist followers data and return the popularity value""" offset = 7 today = datetime.now(tz=pytz.utc) start = today - timedelta(days=offset) params = Params( artist_id=artist_id, start_date=DateUtils.as_str(start), end_date=DateUtils.as_str(today) ) followers = ArtistsViewModel.get_followers_data(params) if followers and len(followers): return followers[-1].get('spotify_popularity') return None @staticmethod def validate_params(params: Params): """Check the parameters provided by the client are compatible before continuing""" err = False id_field = 'artist_id' if not params.artist_id: err = ('Missing at least one identifiying parameter from set: ' f'[{id_field}]') if err: raise InvalidInputError({ 'code': Codes.invalid_input.value, 'description': err, })