Skip to content
Merged
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
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
4.1.0.0 2018-06-01
==================

- Add get session level decisions in Get Decisions APIs.

4.0.1 2018-04-06
==================

Expand Down Expand Up @@ -86,4 +91,3 @@ INCOMPATIBLE CHANGES INTRODUCED IN API V205:
==================

- Just the Python REST client itself.

7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ except sift.client.ApiException:
# request failed
pass

# Get the latest decisions for a session
try:
response = client.get_session_decisions('example_user', 'example_session')
except sift.client.ApiException:
# request failed
pass

# Get the latest decisions for a piece of content
try:
response = client.get_content_decisions('example_user', 'example_content')
Expand Down
32 changes: 32 additions & 0 deletions sift/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,35 @@ def get_content_decisions(self, user_id, content_id, timeout=None):
except requests.exceptions.RequestException as e:
raise ApiException(str(e))

def get_session_decisions(self, user_id, session_id, timeout=None):
"""Gets the decisions for a user's session.

Args:
user_id: The ID of a user.
session_id: The ID of a session.

Returns:
A sift.client.Response object if the call succeeded.
Otherwise, raises an ApiException.

"""
if not isinstance(user_id, self.UNICODE_STRING) or len(user_id.strip()) == 0:
raise ApiException("user_id must be a string")
if not isinstance(session_id, self.UNICODE_STRING) or len(session_id.strip()) == 0:
raise ApiException("session_id must be a string")

if timeout is None:
timeout = self.timeout

try:
return Response(requests.get(
self._session_decisions_url(self.account_id, user_id, session_id),
auth=requests.auth.HTTPBasicAuth(self.api_key, ''),
headers={'User-Agent': self._user_agent()},
timeout=timeout))

except requests.exceptions.RequestException as e:
raise ApiException(str(e))

def apply_session_decision(self, user_id, session_id, properties, timeout=None):
"""Apply decision to session
Expand Down Expand Up @@ -638,6 +667,9 @@ def _user_decisions_url(self, account_id, user_id):
def _order_decisions_url(self, account_id, order_id):
return API3_URL + '/v3/accounts/%s/orders/%s/decisions' % (account_id, order_id)

def _session_decisions_url(self, account_id, user_id, session_id):
return API3_URL + '/v3/accounts/%s/users/%s/sessions/%s/decisions' % (account_id, user_id, session_id)

def _content_decisions_url(self, account_id, user_id, content_id):
return API3_URL + '/v3/accounts/%s/users/%s/content/%s/decisions' % (account_id, user_id, content_id)

Expand Down
2 changes: 1 addition & 1 deletion sift/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
VERSION = '4.0.1'
VERSION = '4.1.0'
API_VERSION = '205'
25 changes: 25 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,12 @@ def test_apply_decision_to_session_fails_with_no_session_id(self):
except Exception as e:
assert(isinstance(e, sift.client.ApiException))

def test_get_session_decisions_fails_with_no_session_id(self):
try:
self.sift_client.get_session_decisions("user_id", None)
except Exception as e:
assert(isinstance(e, sift.client.ApiException))

def test_apply_decision_to_content_fails_with_no_content_id(self):
try:
self.sift_client.apply_content_decision("user_id", None, {})
Expand Down Expand Up @@ -937,6 +943,25 @@ def test_get_order_decisions(self):
assert(response.body['decisions']['payment_abuse']['decision']['id'] == 'decision7')
assert(response.body['decisions']['promotion_abuse']['decision']['id'] == 'good_order')

def test_get_session_decisions(self):
mock_response = mock.Mock()
mock_response.content = '{"decisions":{"account_takeover": {"decision": {"id": "session_decision"},"time": 1461963839151,"webhook_succeeded": true}}}'
mock_response.json.return_value = json.loads(mock_response.content)
mock_response.status_code = 200
mock_response.headers = response_with_data_header()

with mock.patch('requests.get') as mock_get:
mock_get.return_value = mock_response

response = self.sift_client.get_session_decisions('example_user','example_session')
mock_get.assert_called_with(
'https://api3.siftscience.com/v3/accounts/ACCT/users/example_user/sessions/example_session/decisions',
headers=mock.ANY, auth=mock.ANY, timeout=mock.ANY)

assert(isinstance(response, sift.client.Response))
assert(response.is_ok())
assert(response.body['decisions']['account_takeover']['decision']['id'] == 'session_decision')

def test_get_content_decisions(self):
mock_response = mock.Mock()
mock_response.content = '{"decisions":{"content_abuse":{"decision":{"id":"content_looks_bad_content_abuse"},"time":1468517407135,"webhook_succeeded":true}}}'
Expand Down