Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for Events end-point #222

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sparkpost/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .suppression_list import SuppressionList
from .templates import Templates
from .transmissions import Transmissions
from .events import Events


__version__ = '1.3.10'
Expand Down Expand Up @@ -42,6 +43,9 @@ def __init__(self, api_key=None, base_uri=US_API,
# Keeping self.transmission for backwards compatibility.
# Will be removed in a future release.
self.transmission = self.transmissions
self.events = Events(self.base_uri, self.api_key,
self.TRANSPORT_CLASS)


def get_api_key(self):
"Get API key from environment variable"
Expand Down
75 changes: 75 additions & 0 deletions sparkpost/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import base64
import copy
import datetime
import json
import warnings
from email.utils import parseaddr

from .base import Resource
from .base import RequestsTransport
from .exceptions import SparkPostException


class Events(Resource):
"""
Events class used to search events. For detailed
request and response formats, see the `Events API documentation
<https://developers.sparkpost.com/api/events/>.
"""

key = 'events/message'

def __init__(self, base_uri, api_key, transport_class=RequestsTransport):
super(Events, self).__init__(base_uri, api_key, transport_class=transport_class)
self.local_time_offset = 0

def _update_list_and_date_parameters(self, param_dict):
for key, value in param_dict.items():
if isinstance(value, type([])):
param_dict[key] = ",".join(value)
if isinstance(value, datetime.datetime):
param_dict[key] = self.create_date_string(value)
return param_dict

def _fetch_get(self, **kwargs):
uri = "%s" % (self.uri)
params = self._update_list_and_date_parameters(dict(kwargs))
results = self.request('GET', uri, params=params)
return results

def set_local_time_offset_in_hours(self, local_time_offset):
"""

:param local_time_offset: integer for the number of hours for the local time office
This is only used when passing in a datetime object for either the 'from'
or 'to' values with get()
"""
self.local_time_offset = local_time_offset

def get(self, **kwargs):
"""
:param optional kwargs
:param kwargs["from_addresses"] comma-separated string or List[str]
:param kwargs["recipients"] comma-separated string or List[str]
:param kwargs["transmissions"] comma-separated string or List[str]
:param kwargs["from"] string with API-required date formatting OR a datetime object. See
set_local_time_offset_in_hours()
:param kwargs["to"] string with API-required date formatting OR a datetime object. See
set_local_time_offset_in_hours()
:param kwargs["events"] comma-separated string or List[str] with valid event types.
Common event types: bounce, delivery, injection
Documentation for all event types: https://developers.sparkpost.com/api/events/#header-event-types

If kwargs does not have a from/to combination, the API service will usually return all events for the
current day only.

:return: List of dicts, one for each event message being returned
"""

results = self._fetch_get(**kwargs)
return results

def create_date_string(self, local_datetime):
ut_datetime = local_datetime
ut_datetime += datetime.timedelta(hours=self.local_time_offset)
return ut_datetime.strftime("%Y-%m-%dT%H:%M")
89 changes: 89 additions & 0 deletions test/test_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import base64
import datetime
import json
import os
import tempfile
import warnings

import pytest
import responses
import six
from mock import patch

from sparkpost import SparkPost
from sparkpost import Events
from sparkpost.exceptions import SparkPostAPIException, SparkPostException


def test_create_date_string():
timezone_offset = -6
source_date = datetime.datetime(year=2022, month=02, day=28, hour=12, minute=00)
e = Events('uri', 'key')
e.set_local_time_offset_in_hours(timezone_offset)
ut_date_string = e.create_date_string(source_date)

assert "2022-02-28T06:00" == ut_date_string


def test_update_list_and_date_parameters_for_list():
e = Events('uri', 'key')
test_key = "test"
original_string = "item1,item2"
test_dict = {test_key : original_string.split(",")}

converted_dict = e._update_list_and_date_parameters(test_dict)

assert original_string == converted_dict[test_key]


def test_update_list_and_date_parameters_for_datetime():
e = Events('uri', 'key')
e.set_local_time_offset_in_hours(+6)
original_ut = "2022-02-28T12:00"
original_local = "2022-02-28T06:00"
local_datetime = datetime.datetime.strptime(original_local, '%Y-%m-%dT%H:%M')
test_key = "test"
test_dict = {test_key : local_datetime}

converted_dict = e._update_list_and_date_parameters(test_dict)

assert original_ut == converted_dict[test_key]


@responses.activate
def test_get_no_parameters_mocked():
responses.add(
responses.GET,
'https://api.sparkpost.com/api/v1/events/message',
status=200,
content_type='application/json',
body='{"results":[{"mailbox_provider":"gmail","template_version":"0","friendly_from":"[email protected]","subject":"special subject","ip_pool":"default","sending_domain":"sparkpostmail.com","rcpt_tags":[],"type":"delivery","num_retries":"0","mailbox_provider_region":"B2B - Filter","raw_rcpt_to":"[email protected]","msg_from":"[email protected]","recv_method":"esmtp","rcpt_to":"[email protected]","subaccount_id":0,"transmission_id":"8401419633671706792","timestamp":"2022-02-25T03:27:01.000Z","outbound_tls":"1","rcpt_meta":{},"message_id":"62167e4c1862536fd4de","ip_address":"67.231.154.162","queue_time":"6795","recipient_domain":"nowhere.com","event_id":"3693091070679284057","routing_domain":"nowhere.com","sending_ip":"192.168.0.1","template_id":"smtp_8401419633671706792","delv_method":"esmtp","customer_id":99988,"injection_time":"2022-02-25T03:26:54.000Z","msg_size":"15746"}],"total_count":1,"links":{}}'
)
sp = SparkPost('fake-key')
results = sp.events.get()
assert 1 == len(results)


@responses.activate
def test_get_by_sender_email_mocked():
responses.add(
responses.GET,
'https://api.sparkpost.com/api/v1/events/message',
status=200,
content_type='application/json',
body='{"results":[{"mailbox_provider":"gmail","template_version":"0","friendly_from":"[email protected]","subject":"special subject","ip_pool":"default","sending_domain":"sparkpostmail.com","rcpt_tags":[],"type":"delivery","num_retries":"0","mailbox_provider_region":"B2B - Filter","raw_rcpt_to":"[email protected]","msg_from":"[email protected]","recv_method":"esmtp","rcpt_to":"[email protected]","subaccount_id":0,"transmission_id":"8401419633671706792","timestamp":"2022-02-25T03:27:01.000Z","outbound_tls":"1","rcpt_meta":{},"message_id":"62167e4c1862536fd4de","ip_address":"67.231.154.162","queue_time":"6795","recipient_domain":"nowhere.com","event_id":"3693091070679284057","routing_domain":"nowhere.com","sending_ip":"192.168.0.1","template_id":"smtp_8401419633671706792","delv_method":"esmtp","customer_id":99988,"injection_time":"2022-02-25T03:26:54.000Z","msg_size":"15746"}],"total_count":1,"links":{}}'
)
sp = SparkPost('fake-key')

delivery_type = "delivery"
sender_address = "[email protected]"
params = {
"from_addresses" : sender_address,
"from": datetime.datetime(2022, 2, 1, 0, 0),
"to": datetime.datetime(2022, 2, 28, 23, 59),
"events": [delivery_type]
}
results = sp.events.get(params)
assert 1 == len(results)
assert sender_address == results[0]["friendly_from"]
assert delivery_type == results[0]["type"]