"""Message utils.""" import datetime import uuid from src.utils import regions from src.utils import months from src.utils import days from src.common import messages from config import DSP_MAPPING from config import STORE_MAPPING def _notification_enabled( notification_settings, feed_type, notification_type, entity_type): """Check notification_settings for a particular feed type. Args: notification_settings (list[dict]): notification settings for a profile feed_type (str): feed type (e.g. social_spike) entity_type (str): object type that was followed (e.g. participant) Returns: bool: whether the notification is enabled or not. """ for settings in notification_settings: if (settings['notification_type'] == notification_type and settings['feed_type'] == feed_type # noqa:W503 and settings['followed_entity'] == entity_type): # noqa:W503 return True return False def events_with_notifications_enabled( events, notification_settings, feed_type, notification_type): """Return events with notificationn settings enabled.""" enabled_events = [] for event in events: activity_sources = event['object']['activity_sources'] for activity_source in activity_sources: if _notification_enabled( notification_settings, feed_type, notification_type, activity_source): if event not in enabled_events: enabled_events.append(event) return enabled_events def create_social_spike_message(feed_items, _, **user_data): """Process social spike events into sns message.""" messages_list = [] for feed_item in feed_items: verbs_list = feed_item['verb'].split('_') network = verbs_list.pop() notification_type = '_'.join(verbs_list) feed_object = feed_item['object'] participant_name = feed_object['name'] new_followers = feed_object['new_followers'] platform_name, follower_type = messages.get_platform_and_follower_type(network) # noqa:E501 metadata = _message_metadata( user_data, notification_type, { 'participantId': feed_item['actor'] }, { 'socialPlatform': network } ) translate_placeholders = { 'artist': participant_name, 'number': new_followers, 'service': platform_name, 'followers': follower_type } message = messages.create_message_string( _('%(artist)s gained %(number)s %(service)s %(followers)s since yesterday!') % translate_placeholders, # noqa:E501 metadata ) msg_and_metadata = message, metadata messages_list.append(msg_and_metadata) return messages_list def create_trending_track_message(events, _, **user_data): """Process trending track events into sns messages.""" # aggregate by track-country for each event events_agg = {} for event in events: agg_key = ':'.join( [ str(event['object']['track']['id']), event['object']['region'] ] ) if agg_key not in events_agg: events_agg[agg_key] = [] events_agg[agg_key].append(event) # generate message for each track messages_list = [] for agg_key, track_events in events_agg.items(): top_spike = max(track_events, key=lambda x: x['object']['percent_diff']) # noqa: E501 num_dsps = len(set(x['object']['dsp'] for x in track_events)) # get human readable date date_time = datetime.datetime.strptime(top_spike['time'], '%Y-%m-%dT%H:%M:%S.%f') # noqa: E501 month_str = date_time.strftime('%B') day_str = date_time.strftime('%d') # build metadata for notification notification_type = top_spike['verb'] metadata = _message_metadata( user_data, notification_type, { 'isrc': top_spike['object']['track']['isrc'] } ) # human readable dsp name for message dsp_formatted = DSP_MAPPING.get(top_spike['object']['dsp']) # generate different message types if num_dsps == 1: translate_placeholders = { 'songname': top_spike['object']['track']['name'], 'number': top_spike['object']['percent_diff'], 'service': dsp_formatted, 'country': regions.translate_country(top_spike['object']['region'], _), 'month': months.translate_month(month_str, _), 'day': days.translate_day(day_str, _) } message_str = messages.create_message_string( _('%(songname)s had a %(number)s%% increase in streams on %(service)s in %(country)s on %(month)s %(day)s') % translate_placeholders, # noqa:E501 metadata ) else: num_other_dsps = num_dsps - 1 dsp_str = 'platforms' if num_other_dsps > 1 else 'platform' translate_placeholders = { 'songname': top_spike['object']['track']['name'], 'service': dsp_formatted, 'servicecount': num_other_dsps, 'platforms': dsp_str, 'country': regions.translate_country(top_spike['object']['region'], _), 'month': months.translate_month(month_str, _), 'day': days.translate_day(day_str, _) } message_str = messages.create_message_string( _('%(songname)s had an increase in streams on %(service)s and %(servicecount)s other %(platforms)s in %(country)s on %(month)s %(day)s') % translate_placeholders, # noqa:E501 metadata ) msg_and_metadata = message_str, metadata messages_list.append(msg_and_metadata) return messages_list def create_playlist_placement_message(events, _, **user_data): """Process playlist placement events into sns message.""" events_by_isrc = {} for event in events: isrc = event['object']['sound_recording']['isrc'] if isrc not in events_by_isrc: events_by_isrc[isrc] = [] events_by_isrc[isrc].append(event) messages_list = [] for key, value in events_by_isrc.items(): top_pl = max(value, key=lambda x: x['object']['playlist']['rank']) song_name = value[0]['object']['sound_recording']['name'] top_pl_name = top_pl['object']['playlist']['name'] platform = DSP_MAPPING.get(top_pl['object']['playlist']['dsp']) playlists = sorted([event['object']['playlist'] for event in value], key=lambda x: x['rank']) # noqa:E501 playlist_ids = [] for pl in playlists: if pl['id'] not in playlist_ids: playlist_ids.append(pl['id']) num_playlists = len(playlist_ids) metadata = _message_metadata( user_data, top_pl['verb'], { 'isrc': value[0]['object']['sound_recording']['isrc'], 'playlistIds': playlist_ids[:1], 'playlists': list(map( lambda p: {'id': p['id'], 'store_id': str(p.get('store_id', ''))}, playlists[:1] )) } ) if num_playlists == 1: translate_placeholders = { 'songname': song_name, 'playlistname': top_pl_name, 'service': platform, } message = messages.create_message_string( _('%(songname)s has been added to %(playlistname)s on %(service)s!') % translate_placeholders, # noqa:E501 metadata ) else: num_playlists = str(num_playlists - 1) fix_plurals = 's' if int(num_playlists) > 1 else '' translate_placeholders = { 'songname': song_name, 'playlistname': top_pl_name, 'service': platform, 'playlistcount': num_playlists, 'plurals': fix_plurals, } message = messages.create_message_string( _('%(songname)s has been added to %(playlistname)s on %(service)s and %(playlistcount)s other playlist%(plurals)s!') % translate_placeholders, # noqa:E501 metadata ) msg_and_metadata = message, metadata messages_list.append(msg_and_metadata) return messages_list def create_streams_updated_message(events, _, **user_data): """Process streams updated events into sns message.""" messages_list = [] for event in events: date = datetime.date.fromisoformat(event['object']['available_date']) month_str = date.strftime('%B') day_str = date.strftime('%d') metadata = _message_metadata( user_data, event['verb'], { 'store_id': event['object']['store_id'], } ) translate_placeholders = { 'store': STORE_MAPPING[event['object']['store_id']], 'month': months.translate_month(month_str, _), 'day': days.translate_day(day_str, _) } message = messages.create_message_string( _('%(store)s for %(month)s %(day)s are now updated.') % translate_placeholders, # noqa:E501, metadata ) messages_list.append((message, metadata)) return messages_list def _message_metadata( user_data, event_type, payload, extras={}): """Create metadata about notification event. Args: user_data (dict): see src.app.send_message() for dict format event_type (str): category of source event payload (dict): free form object of more event details Returns: dict """ metadata = { 'profileId': user_data['profile_id'], 'profileType': user_data['profile_type'], 'identityId': user_data['identity_id'], 'brand': user_data.get('brand'), 'notificationId': str(uuid.uuid4()), 'type': event_type, 'payload': payload } for k, v in extras.items(): if k not in metadata: metadata[k] = v return {'data': metadata}