diff --git a/crossengage/client.py b/crossengage/client.py index 22a9884..d236597 100644 --- a/crossengage/client.py +++ b/crossengage/client.py @@ -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' @@ -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: diff --git a/tests/test_client.py b/tests/test_client.py index aa491cb..d2a9fa4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -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', @@ -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)