Webhooks: default tracking event tags=[], metadata={}

If a tracking event doesn't contain tags or metadata, set the event
record fields to tags=[] or metadata={} to simplify checking values.

Closes #67
This commit is contained in:
medmunds
2017-06-30 16:56:36 -07:00
parent e39614e5a5
commit fc59707133
11 changed files with 25 additions and 18 deletions

View File

@@ -32,11 +32,11 @@ class AnymailTrackingEvent(AnymailEvent):
self.click_url = kwargs.pop('click_url', None) # str self.click_url = kwargs.pop('click_url', None) # str
self.description = kwargs.pop('description', None) # str, usually human-readable, not normalized self.description = kwargs.pop('description', None) # str, usually human-readable, not normalized
self.message_id = kwargs.pop('message_id', None) # str, format may vary self.message_id = kwargs.pop('message_id', None) # str, format may vary
self.metadata = kwargs.pop('metadata', None) # dict self.metadata = kwargs.pop('metadata', {}) # dict
self.mta_response = kwargs.pop('mta_response', None) # str, may include SMTP codes, not normalized self.mta_response = kwargs.pop('mta_response', None) # str, may include SMTP codes, not normalized
self.recipient = kwargs.pop('recipient', None) # str email address (just the email portion; no name) self.recipient = kwargs.pop('recipient', None) # str email address (just the email portion; no name)
self.reject_reason = kwargs.pop('reject_reason', None) # normalized to a RejectReason str self.reject_reason = kwargs.pop('reject_reason', None) # normalized to a RejectReason str
self.tags = kwargs.pop('tags', None) # list of str self.tags = kwargs.pop('tags', []) # list of str
self.user_agent = kwargs.pop('user_agent', None) # str self.user_agent = kwargs.pop('user_agent', None) # str

View File

@@ -113,7 +113,7 @@ class MailgunTrackingWebhookView(MailgunBaseWebhookView):
try: try:
headers = json.loads(esp_event['message-headers']) headers = json.loads(esp_event['message-headers'])
except (KeyError, ): except (KeyError, ):
metadata = None metadata = {}
else: else:
variables = [value for [field, value] in headers variables = [value for [field, value] in headers
if field == 'X-Mailgun-Variables'] if field == 'X-Mailgun-Variables']
@@ -121,10 +121,10 @@ class MailgunTrackingWebhookView(MailgunBaseWebhookView):
# Each X-Mailgun-Variables value is JSON. Parse and merge them all into single dict: # Each X-Mailgun-Variables value is JSON. Parse and merge them all into single dict:
metadata = combine(*[json.loads(value) for value in variables]) metadata = combine(*[json.loads(value) for value in variables])
else: else:
metadata = None metadata = {}
# tags are sometimes delivered as X-Mailgun-Tag fields, sometimes as tag # tags are sometimes delivered as X-Mailgun-Tag fields, sometimes as tag
tags = esp_event.getlist('tag', esp_event.getlist('X-Mailgun-Tag', None)) tags = esp_event.getlist('tag', esp_event.getlist('X-Mailgun-Tag', []))
return AnymailTrackingEvent( return AnymailTrackingEvent(
event_type=event_type, event_type=event_type,

View File

@@ -128,12 +128,12 @@ class MandrillTrackingWebhookView(MandrillBaseWebhookView):
try: try:
metadata = esp_event['msg']['metadata'] metadata = esp_event['msg']['metadata']
except KeyError: except KeyError:
metadata = None metadata = {}
try: try:
tags = esp_event['msg']['tags'] tags = esp_event['msg']['tags']
except KeyError: except KeyError:
tags = None tags = []
return AnymailTrackingEvent( return AnymailTrackingEvent(
click_url=esp_event.get('url', None), click_url=esp_event.get('url', None),

View File

@@ -89,7 +89,7 @@ class PostmarkTrackingWebhookView(PostmarkBaseWebhookView):
try: try:
tags = [esp_event['Tag']] tags = [esp_event['Tag']]
except KeyError: except KeyError:
tags = None tags = []
return AnymailTrackingEvent( return AnymailTrackingEvent(
description=esp_event.get('Description', None), description=esp_event.get('Description', None),

View File

@@ -72,7 +72,7 @@ class SendGridTrackingWebhookView(SendGridBaseWebhookView):
if len(metadata_keys) > 0: if len(metadata_keys) > 0:
metadata = {key: esp_event[key] for key in metadata_keys} metadata = {key: esp_event[key] for key in metadata_keys}
else: else:
metadata = None metadata = {}
return AnymailTrackingEvent( return AnymailTrackingEvent(
event_type=event_type, event_type=event_type,
@@ -82,7 +82,7 @@ class SendGridTrackingWebhookView(SendGridBaseWebhookView):
recipient=esp_event.get('email', None), recipient=esp_event.get('email', None),
reject_reason=reject_reason, reject_reason=reject_reason,
mta_response=mta_response, mta_response=mta_response,
tags=esp_event.get('category', None), tags=esp_event.get('category', []),
metadata=metadata, metadata=metadata,
click_url=esp_event.get('url', None), click_url=esp_event.get('url', None),
user_agent=esp_event.get('useragent', None), user_agent=esp_event.get('useragent', None),

View File

@@ -108,7 +108,7 @@ class SparkPostTrackingWebhookView(SparkPostBaseWebhookView):
tag = event['campaign_id'] # not 'rcpt_tags' -- those don't come from sending a message tag = event['campaign_id'] # not 'rcpt_tags' -- those don't come from sending a message
tags = [tag] if tag else None tags = [tag] if tag else None
except KeyError: except KeyError:
tags = None tags = []
try: try:
reject_reason = self.reject_reasons.get(event['bounce_class'], RejectReason.OTHER) reject_reason = self.reject_reasons.get(event['bounce_class'], RejectReason.OTHER)
@@ -129,7 +129,7 @@ class SparkPostTrackingWebhookView(SparkPostBaseWebhookView):
mta_response=event.get('raw_reason', None), mta_response=event.get('raw_reason', None),
# description=???, # description=???,
tags=tags, tags=tags,
metadata=event.get('rcpt_meta', None) or None, # message + recipient metadata metadata=event.get('rcpt_meta', None) or {}, # message + recipient metadata
click_url=event.get('target_link_url', None), click_url=event.get('target_link_url', None),
user_agent=event.get('user_agent', None), user_agent=event.get('user_agent', None),
esp_event=raw_event, esp_event=raw_event,

View File

@@ -139,12 +139,14 @@ Normalized tracking event
.. attribute:: metadata .. attribute:: metadata
A `dict` of unique data attached to the message, or `None`. A `dict` of unique data attached to the message. Will be empty if the ESP
doesn't provide metadata with its tracking events.
(See :attr:`AnymailMessage.metadata <anymail.message.AnymailMessage.metadata>`.) (See :attr:`AnymailMessage.metadata <anymail.message.AnymailMessage.metadata>`.)
.. attribute:: tags .. attribute:: tags
A `list` of `str` tags attached to the message, or `None`. A `list` of `str` tags attached to the message. Will be empty if the ESP
doesn't provide tags with its tracking events.
(See :attr:`AnymailMessage.tags <anymail.message.AnymailMessage.tags>`.) (See :attr:`AnymailMessage.tags <anymail.message.AnymailMessage.tags>`.)
.. attribute:: reject_reason .. attribute:: reject_reason

View File

@@ -109,6 +109,8 @@ class MailgunDeliveryTestCase(WebhookTestCase):
self.assertEqual(event.event_id, "06c96bafc3f42a66b9edd546347a2fe18dc23461fe80dc52f0") self.assertEqual(event.event_id, "06c96bafc3f42a66b9edd546347a2fe18dc23461fe80dc52f0")
self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.recipient, "recipient@example.com")
self.assertEqual(querydict_to_postdict(event.esp_event), raw_event) self.assertEqual(querydict_to_postdict(event.esp_event), raw_event)
self.assertEqual(event.tags, [])
self.assertEqual(event.metadata, {})
def test_dropped_bounce(self): def test_dropped_bounce(self):
raw_event = mailgun_sign({ raw_event = mailgun_sign({

View File

@@ -78,6 +78,7 @@ class PostmarkDeliveryTestCase(WebhookTestCase):
self.assertEqual(event.message_id, "883953f4-6105-42a2-a16a-77a8eac79483") self.assertEqual(event.message_id, "883953f4-6105-42a2-a16a-77a8eac79483")
self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.recipient, "recipient@example.com")
self.assertEqual(event.tags, ["welcome-email"]) self.assertEqual(event.tags, ["welcome-email"])
self.assertEqual(event.metadata, {})
def test_open_event(self): def test_open_event(self):
raw_event = { raw_event = {
@@ -106,3 +107,5 @@ class PostmarkDeliveryTestCase(WebhookTestCase):
self.assertEqual(event.message_id, "f4830d10-9c35-4f0c-bca3-3d9b459821f8") self.assertEqual(event.message_id, "f4830d10-9c35-4f0c-bca3-3d9b459821f8")
self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.recipient, "recipient@example.com")
self.assertEqual(event.user_agent, "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0") self.assertEqual(event.user_agent, "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0")
self.assertEqual(event.tags, [])
self.assertEqual(event.metadata, {})

View File

@@ -73,8 +73,8 @@ class SendGridDeliveryTestCase(WebhookTestCase):
self.assertEqual(event.event_id, "nOSv8m0eTQ-vxvwNwt3fZQ") self.assertEqual(event.event_id, "nOSv8m0eTQ-vxvwNwt3fZQ")
self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.recipient, "recipient@example.com")
self.assertEqual(event.mta_response, "250 2.0.0 OK 1461095248 m143si2210036ioe.159 - gsmtp ") self.assertEqual(event.mta_response, "250 2.0.0 OK 1461095248 m143si2210036ioe.159 - gsmtp ")
self.assertEqual(event.tags, None) self.assertEqual(event.tags, [])
self.assertEqual(event.metadata, None) self.assertEqual(event.metadata, {})
def test_dropped_invalid_event(self): def test_dropped_invalid_event(self):
raw_events = [{ raw_events = [{

View File

@@ -97,8 +97,8 @@ class SparkPostDeliveryTestCase(WebhookTestCase):
self.assertIsInstance(event, AnymailTrackingEvent) self.assertIsInstance(event, AnymailTrackingEvent)
self.assertEqual(event.event_type, "delivered") self.assertEqual(event.event_type, "delivered")
self.assertEqual(event.recipient, "Recipient@example.com") self.assertEqual(event.recipient, "Recipient@example.com")
self.assertEqual(event.tags, None) self.assertEqual(event.tags, [])
self.assertEqual(event.metadata, None) self.assertEqual(event.metadata, {})
def test_bounce_event(self): def test_bounce_event(self):
raw_events = [{ raw_events = [{