"""Util functions related to extracting a notification from a sqs.Message.""" import base64 import json import re from notifications_delivery.constants.exceptions import IgnoredMessageError from notifications_delivery.constants.notifications import ( FEED_ID_ENCODING, ORCHARD_NOTIFICATIONS_REQUIRED_FIELDS, ) def parse_message(message, fmt): """Parse message and return a formatted notification dict. Args: message (sqs.Message): message pulled from SQS-message. fmt (str): message type Returns: dict: the formatted notification. """ notification = None if fmt == 'orchard': notification = parse_orchard_message(message) elif fmt == 'stream': notification = parse_stream_message(message) return notification def parse_orchard_message(notification): """Parse and validate a message coming from The Orchard. Args: notification (dict): the message body Returns: dict: the validated notification """ if not all(key in notification for key in ORCHARD_NOTIFICATIONS_REQUIRED_FIELDS): return None return notification def parse_stream_message(message_body): """Parse and validate a message coming from Stream (getstream.io). Args: message_body (str): the base64 encoded message body Returns: dict: the validated notification """ try: decoded_message_body = base64.b64decode(message_body) stream_message = json.loads(decoded_message_body) return map_to_notification(stream_message) except IgnoredMessageError: # Special case. Empty messages should be ignored. Just rerise here. Will be handled further. raise except Exception: return None def map_to_notification(stream_message): """Map a Stream message to an Orchard notification. Args: stream_message (list): the Stream message Returns: dict: the orchard notification """ user_feeds = [item['feed'] for item in stream_message] user_ids = [] user_emails = [] for user_feed in user_feeds: user_feed_id = user_feed.split(':')[1] if re.match('(oa|alw)_[0-9]+', user_feed_id): user_ids.append(user_feed_id.replace('_', ':')) else: for key, value in FEED_ID_ENCODING.items(): user_feed_id = user_feed_id.replace(key, value) user_emails.append(user_feed_id) if not stream_message[0]['new']: raise IgnoredMessageError('Message is empty') activity = stream_message[0]['new'][0] # origin is set by getstream when the activity flows through follow stream. # new activities will be writen directly to user stream with original_feed. feed = activity.get('origin') or activity.get('original_feed') if not feed: return None feed_name = feed.split(':')[0] feed_id = feed.split(':')[1] if activity.get('template_name'): template = activity.get('template_name') elif 'orchard_trending_tracks_' in feed_name: template = 'trending_tracks' elif 'email_notification_rejection' in feed_name: template = 'release_rejection' else: template = feed_name.replace('label_', '', 1) return { 'user_ids': user_ids, 'user_emails': user_emails, 'feed_name': feed_name, 'feed_id': feed_id, 'template': template, 'payload': activity }