From dab7dac8436f8a2f3078e938d6b679714e4336e4 Mon Sep 17 00:00:00 2001 From: Anvith Shivakumara Date: Tue, 16 Apr 2019 14:48:21 +0200 Subject: [PATCH 1/3] Add crossengage opt-out endpoints --- crossengage/client.py | 29 +++++++++++++++++++++++ tests/test_client.py | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/crossengage/client.py b/crossengage/client.py index 22a9884..17ce33a 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,34 @@ 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): + # type: (dict) -> dict + """ + Fetch User Opt-Out status by id. + :param user: dict of payload (id, email, businessUnit, firstName, lastName, birthday, createdAt, gender, silo) + :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, user['silo'] + ) + 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..348b844 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', + 'silo': '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) + + # THEN + requests.put.assert_called_once_with( + self.CROSSENGAGE_URL + 'users/1234/optout-status?channelType=' + self.user['silo'], + data='{"optOut": true}', + headers=self.default_headers_api_v1, + timeout=30 + ) + + self.assertEqual(expected_response, result) From 1ac3a1637c904d9ea9467c9d649fb5bc40b8bb4d Mon Sep 17 00:00:00 2001 From: Anvith Shivakumara Date: Tue, 16 Apr 2019 16:58:55 +0200 Subject: [PATCH 2/3] Address feedback --- crossengage/client.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crossengage/client.py b/crossengage/client.py index 17ce33a..d236597 100644 --- a/crossengage/client.py +++ b/crossengage/client.py @@ -364,18 +364,20 @@ def get_user_opt_out_status(self, user_id): 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): - # type: (dict) -> dict + def update_user_opt_out_status(self, user_id, channel_name): + # type: (str, str) -> dict """ Fetch User Opt-Out status by id. - :param user: dict of payload (id, email, businessUnit, firstName, lastName, birthday, createdAt, gender, silo) + :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, user['silo'] + 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") From da57b7a7d70ea1ccb30e75d61b42832f6d0cc174 Mon Sep 17 00:00:00 2001 From: Anvith Shivakumara Date: Tue, 16 Apr 2019 17:00:42 +0200 Subject: [PATCH 3/3] Fix unit tests --- tests/test_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 348b844..d2a9fa4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -56,7 +56,7 @@ def setUp(self): 'birthday': '1991-11-07', 'createdAt': '2015-10-02T08:23:53Z', 'gender': 'male', - 'silo': 'MAIL' + 'channel': 'MAIL' } self.default_headers_api_v1 = { 'X-XNG-AuthToken': 'SOME_TOKEN', @@ -668,11 +668,11 @@ def test_update_user_opt_out_status(self): self.client.requests = requests # WHEN - result = self.client.update_user_opt_out_status(self.user) + 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['silo'], + self.CROSSENGAGE_URL + 'users/1234/optout-status?channelType=' + self.user['channel'], data='{"optOut": true}', headers=self.default_headers_api_v1, timeout=30