Skip to content
This repository was archived by the owner on Sep 6, 2025. It is now read-only.
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
31 changes: 31 additions & 0 deletions crossengage/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class CrossengageClient(object):
USER_BULK_ENDPOINT = "{0}/batch".format(USER_ENDPOINT)
TRACK_USER_TASK_ENDPOINT = "{0}/track".format(USER_ENDPOINT)
EVENTS_ENDPOINT = 'events'
OPTOUT_ENDPOINT = 'optout-status'

REQUEST_GET = 'get'
REQUEST_PUT = 'put'
Expand Down Expand Up @@ -350,6 +351,36 @@ def track_user_task(self, tracking_id):

return r.status_code, body

def get_user_opt_out_status(self, user_id):
# type: (str) -> dict
"""
Fetch User Opt-Out status by id.
:param user_id: User external ID
:return: json dict response, for example:
{
"optOut": false
}
"""
self.request_url = "{0}/{1}/{2}/{3}".format(self.API_URL, self.USER_ENDPOINT, user_id, self.OPTOUT_ENDPOINT)
return self.__create_request(payload={}, request_type=self.REQUEST_GET, version="v1")

def update_user_opt_out_status(self, user_id, channel_name):
# type: (str, str) -> dict
"""
Fetch User Opt-Out status by id.
:param user_id: User ID
:param channel_name: Name of the channel to opt out user from. It has to be one of MAIL, BROWSER_NOTIFICATION,
ONSITE_DISPLAY, EXIT_INTENT, PUSH_NOTIFICATION, DIRECT_MAIL or SMS
:return: json dict response, for example:
{
"optOut": true
}
"""
self.request_url = "{0}/{1}/{2}/{3}?channelType={4}".format(
self.API_URL, self.USER_ENDPOINT, user_id, self.OPTOUT_ENDPOINT, channel_name
)
return self.__create_request(payload={"optOut": True}, request_type=self.REQUEST_PUT, version="v1")

def __create_request(self, payload, request_type, version):
headers = update_dict(self.default_headers, {self.API_VERSION_HEADER: self.API_VERSIONS[version]})
try:
Expand Down
54 changes: 54 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def setUp(self):
'birthday': '1991-11-07',
'createdAt': '2015-10-02T08:23:53Z',
'gender': 'male',
'channel': 'MAIL'
}
self.default_headers_api_v1 = {
'X-XNG-AuthToken': 'SOME_TOKEN',
Expand Down Expand Up @@ -625,3 +626,56 @@ def test_track_user_task_not_found(self):
)

self.assertEqual(result, (codes.not_found, None))

def test_get_user_opt_out_status(self):
"""Crossengage returns status code 200"""
# GIVEN
expected_response = self.user.copy()
expected_response.update({"status_code": codes.ok})
response = Mock(status_code=codes.ok)
response.json.return_value = expected_response
requests = Mock()
requests.get.return_value = response

requests = Mock()
requests.get.return_value = response
self.client.requests = requests

# WHEN
result = self.client.get_user_opt_out_status(self.user['id'])

# THEN
requests.get.assert_called_once_with(
self.CROSSENGAGE_URL + 'users/1234/optout-status',
headers=self.default_headers_api_v1,
timeout=30
)

self.assertEqual(expected_response, result)

def test_update_user_opt_out_status(self):
"""Crossengage returns status code 200"""
# GIVEN
expected_response = self.user.copy()
expected_response.update({"status_code": codes.ok})
response = Mock(status_code=codes.ok)
response.json.return_value = expected_response
requests = Mock()
requests.get.return_value = response

requests = Mock()
requests.put.return_value = response
self.client.requests = requests

# WHEN
result = self.client.update_user_opt_out_status(self.user['id'], self.user['channel'])

# THEN
requests.put.assert_called_once_with(
self.CROSSENGAGE_URL + 'users/1234/optout-status?channelType=' + self.user['channel'],
data='{"optOut": true}',
headers=self.default_headers_api_v1,
timeout=30
)

self.assertEqual(expected_response, result)