diff --git a/bayonet/bayonet.py b/bayonet/bayonet.py index d29f364..c8d690e 100644 --- a/bayonet/bayonet.py +++ b/bayonet/bayonet.py @@ -13,11 +13,9 @@ class _BayonetTransport(object): Responsible for implementing the wire protocol for making requests to the Bayonet API. """ - _SUPPORTED_API_VERSIONS = ['1'] _DEFAULT_DOMAIN = '.bayonet.io' _HOST_API = 'api' - _HOST_FINGERPRINTING = 'fingerprinting' # RPC style means that the argument and result of a route are contained in # the HTTP body. @@ -25,7 +23,6 @@ class _BayonetTransport(object): def __init__(self, api_key, - api_version, user_agent=None, headers=None): """ @@ -40,15 +37,6 @@ def __init__(self, 'Expected dict, got %r' % headers self.api_key = api_key - - if not api_version: - raise InvalidClientSetupError("Please specify Api version") - elif api_version not in BayonetClient._SUPPORTED_API_VERSIONS: - raise InvalidClientSetupError( - "This library does not support version specified. Consider updating your dependencies") - else: - self.api_version = api_version - self._headers = headers base_user_agent = 'OfficialBayonetPythonSDK' @@ -64,10 +52,7 @@ def __init__(self, BayonetClient._DEFAULT_DOMAIN) self._api_hostname = os.environ.get('BAYONET_API_HOST', 'api' + self._domain) - self._fingerprinting_api_hostname = os.environ.get('BAYONET_FINGERPRINTING_API_HOST', - 'fingerprinting' + self._domain) - - self._api_version_namespace = "v" + api_version + self._api_version_namespace = "v2" def fully_qualified_api_hostname(self): return 'https://{api_host_name}/{api_version_namespace}'.format( @@ -75,12 +60,6 @@ def fully_qualified_api_hostname(self): api_version_namespace=self._api_version_namespace ) - def fully_qualified_fingerprinting_api_hostname(self): - return 'https://{fingerprinting_api_hostname}/{api_version_namespace}'.format( - fingerprinting_api_hostname=self._fingerprinting_api_hostname, - api_version_namespace=self._api_version_namespace - ) - def request(self, route, json_params): """ Makes a request to the Bayonet API and in the process validates @@ -108,11 +87,8 @@ def request_json_string(self, """ # Fully qualified hostname fq_hostname = self.fully_qualified_api_hostname() - if route == "/get-fingerprint-data": - fq_hostname = self.fully_qualified_fingerprinting_api_hostname() url = "{}{}".format(fq_hostname, route) - headers = {'User-Agent': self._user_agent, 'Content-Type': 'application/json'} if self._headers: @@ -125,8 +101,10 @@ def request_json_string(self, data=request_json_arg) if resp.status_code == 200: + s.close() return BayonetResponse(resp) else: + s.close() raise BayonetError('', request_json_arg, headers, resp.status_code, resp.content) diff --git a/bayonet/bayonet_base.py b/bayonet/bayonet_base.py index 8cb4ee0..691257e 100644 --- a/bayonet/bayonet_base.py +++ b/bayonet/bayonet_base.py @@ -5,9 +5,8 @@ class BayonetBase(object): __metaclass__ = ABCMeta - def __init__(self, api_key, version): + def __init__(self, api_key): self.api_key = api_key - self.version = version @abstractmethod def request(self, route, arg): @@ -15,21 +14,33 @@ def request(self, route, arg): def consulting(self, params): serialized = self.json_from_params(params) - return self.request('/consulting', serialized) + return self.request('/sigma/consult', serialized) - def feedback(self, params): + def update_transaction(self, params): serialized = self.json_from_params(params) - return self.request('/feedback', serialized) + return self.request('/sigma/update-transaction', serialized) def feedback_historical(self, params): serialized = self.json_from_params(params) - return self.request('/feedback-historical', serialized) - - def get_fingerprint_data(self, params): + return self.request('/sigma/feedback-historical', serialized) + + def blocklist_add(self, params): + serialized = self.json_from_params(params) + return self.request('/sigma/labels/block/add', serialized) + + def blocklist_remove(self, params): + serialized = self.json_from_params(params) + return self.request('/sigma/labels/block/remove', serialized) + + def whitelist_add(self, params): + serialized = self.json_from_params(params) + return self.request('/sigma/labels/whitelist/add', serialized) + + def whitelist_add(self, params): serialized = self.json_from_params(params) - return self.request('/get-fingerprint-data', serialized) + return self.request('/sigma/labels/whitelist/remove', serialized) def json_from_params(self, params): # Add api_key to params - params['api_key'] = self.api_key + params['auth'] = {'api_key': self.api_key} return json.dumps(params) diff --git a/bayonet/response.py b/bayonet/response.py index 21bf867..19f1654 100644 --- a/bayonet/response.py +++ b/bayonet/response.py @@ -4,8 +4,8 @@ class BayonetResponse(object): def __init__(self, response): parsed_response = json.loads(response.content) - if 'feedback_api_trans_code' in parsed_response: - self.feedback_api_trans_code = parsed_response['feedback_api_trans_code'] + if 'bayonet_tracking_id' in parsed_response: + self.bayonet_tracking_id = parsed_response['bayonet_tracking_id'] else: self.feedback_api_trans_code = None if 'rules_triggered' in parsed_response: @@ -32,8 +32,4 @@ def __init__(self, response): self.request_body = parsed_response['request_body'] else: self.request_body = None - if 'bayonet_fingerprint' in parsed_response: - self.bayonet_fingerprint = parsed_response['bayonet_fingerprint'] - else: - self.bayonet_fingerprint = None self.raw = parsed_response diff --git a/setup.py b/setup.py index 1b59493..7ac1f41 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import warnings from setuptools import setup -version = "1.1.0" +version = "2.0.0" path, script = os.path.split(sys.argv[0]) os.chdir(os.path.abspath(path)) @@ -41,6 +41,8 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules", ]) diff --git a/test/test_bayonet.py b/test/test_bayonet.py index 77c2c24..56fcc4e 100644 --- a/test/test_bayonet.py +++ b/test/test_bayonet.py @@ -12,97 +12,110 @@ file=sys.stderr) sys.exit(1) -api_version = os.environ.get('API_VERSION') -if api_version is None: - print('Set API_VERSION environment variable to a valid token.', - file=sys.stderr) - sys.exit(1) - invalid_api_key = "da2da838-6311-4646-805f-2466954b1a11" params_consulting = { - "channel": "ecommerce", - "cardholder_name": "test_python_cardholder_name", - "product_name": "test_python_product_name", - "consumer_name": "test_python_consumer_name", - "transaction_time": "1476813671", - "payment_method": "card", - "transaction_amount": "500.00", + "email": "test_python@bayonet.io", + "consumer_name": "test python consumer name", + "consumer_internal_id": "test_python_1", + "cardholder_name": "test python cardholder name", + "telephone": "9999999999", "card_number": "4111111111111111", + "transaction_amount": 500.00, "currency_code": "MXN", - "coupon": "test_python_coupon", - "telephone": "9999999999", - "expedited_shipping": False, - "email": "test_python@bayonet.io", - "payment_gateway": "stripe", - "device_fingerprint": "test_python_d_f", "shipping_address": { - "address_line_1": "test_python_line_1", - "address_line_2": "test_python_line_2", + "line_1": "test_python_line_1", + "line_2": "test_python_line_2", "city": "Mexico DF", "state": "Mexico DF", "country": "MEX", "zip_code": "111111" - } -} - -params_feedback = { - "transaction_status": "success", - "transaction_id": "test_python", - "feedback_api_trans_code": "xxx" + }, + "billing_address": { + "line_1": "test_python_line_1", + "line_2": "test_python_line_2", + "city": "Mexico DF", + "state": "Mexico DF", + "country": "MEX", + "zip_code": "111111" + }, + "payment_method": "card", + "transaction_time": 1476813671, + "order_id": "test_python_123", + "payment_gateway": "stripe", + "channel": "ecommerce", + "coupon": "test_python_coupon", + "expedited_shipping": False, + "products": [ + { + "product_id": "1", + "product_name": "product_1", + "product_price": 500.00, + "product_category": "test" + } + ] } -params_chargeback_feedback = { - "type": "chargeback", - "chargeback_time": "1425518410", - "chargeback_reason": "fraud", - "transaction_id": "test_python" +params_update_transaction = { + "transaction_status": "bank_decline", + "bayonet_tracking_id": "test_python_123" } - params_feedback_historical = { - "channel": "ecommerce", - "type": "transaction", - "cardholder_name": "test_python_cardholder_name", - "product_name": "test_python_product_name", - "consumer_name": "test_python_consumer_name", - "transaction_time": "1476813671", - "transaction_id": "test_python_f_h", - "transaction_status": "success", - "payment_method": "card", - "transaction_amount": "500.00", + "email": "test_python@bayonet.io", + "consumer_name": "test python consumer name", + "consumer_internal_id": "test_python_1", + "cardholder_name": "test python cardholder name", + "telephone": "9999999999", "card_number": "4111111111111111", + "transaction_amount": 500.00, "currency_code": "MXN", - "coupon": "test_python_coupon", - "telephone": "9999999999", - "expedited_shipping": False, - "email": "test_python@bayonet.io", - "payment_gateway": "stripe", - "device_fingerprint": "test_python_df", "shipping_address": { - "address_line_1": "test_python_line_1", - "address_line_2": "test_python_line_2", + "line_1": "test_python_line_1", + "line_2": "test_python_line_2", "city": "Mexico DF", "state": "Mexico DF", "country": "MEX", "zip_code": "111111" - } + }, + "billing_address": { + "line_1": "test_python_line_1", + "line_2": "test_python_line_2", + "city": "Mexico DF", + "state": "Mexico DF", + "country": "MEX", + "zip_code": "111111" + }, + "payment_method": "card", + "transaction_time": 1476813671, + "order_id": "test_python_123", + "payment_gateway": "stripe", + "channel": "ecommerce", + "coupon": "test_python_coupon", + "expedited_shipping": False, + "products": [ + { + "product_id": "1", + "product_name": "product_1", + "product_price": 500.00, + "product_category": "test" + } + ], + "transaction_status": "success" } -params_get_fingerprint_data = { - "bayonet_fingerprint_token": "xxx" +params_blocklist_invalid = { + "email": "arandommailtotestxxx@xxx.com" } -feedback_api_trans_code = "" +params_blocklist_valid = { + "email": "test_python@bayonet.io" +} class TestBayonet(unittest.TestCase): def setUp(self): - self.client = bayonet.BayonetClient(api_key, api_version) - - def test_bad_client_setup(self): - with self.assertRaises(bayonet.InvalidClientSetupError): - bayonet.BayonetClient(api_key, '2.0') + self.client = bayonet.BayonetClient(api_key) def test_default_client_user_agent(self): self.assertIsNone(self.client._raw_user_agent) @@ -113,11 +126,11 @@ def test_default_api_hostname(self): self.assertEqual(self.client._api_hostname, 'api.bayonet.io') def test_client_api_version_namespace(self): - self.assertEqual(self.client._api_version_namespace, 'v1') + self.assertEqual(self.client._api_version_namespace, 'v2') def test_fully_qualified_api_host_name(self): self.assertEqual(self.client.fully_qualified_api_hostname(), - 'https://api.bayonet.io/v1') + 'https://api.bayonet.io/v2') def test_client_must_respond_to__request(self): assert type(self.client.request) is MethodType @@ -125,8 +138,8 @@ def test_client_must_respond_to__request(self): class TestConsult(unittest.TestCase): def setUp(self): - self.client = bayonet.BayonetClient(api_key, api_version) - self.invalid_client = bayonet.BayonetClient(invalid_api_key, api_version) + self.client = bayonet.BayonetClient(api_key) + self.invalid_client = bayonet.BayonetClient(invalid_api_key) def test_should_return_error_on_invalid_api_key(self): with self.assertRaises(bayonet.BayonetError): @@ -136,79 +149,85 @@ def test_should_validate_api_key(self): try: self.invalid_client.consulting(params_consulting) except bayonet.BayonetError as e: - self.assertEqual(e.reason_code, "11") + self.assertEqual(e.reason_code, 12) def test_should_return_success(self): r = self.client.consulting(params_consulting) - global feedback_api_trans_code - feedback_api_trans_code = r.feedback_api_trans_code - self.assertEqual(r.reason_code, "00") + global bayonet_tracking_id + bayonet_tracking_id = r.bayonet_tracking_id + self.assertEqual(r.reason_code, 0) - def test_should_return_feedback_api_trans_code(self): + def test_should_return_bayonet_tracking_id(self): r = self.client.consulting(params_consulting) - assert r.feedback_api_trans_code is not None + assert r.bayonet_tracking_id is not None -class TestFeedback(unittest.TestCase): +class TestUpdateTransaction(unittest.TestCase): def setUp(self): - self.client = bayonet.BayonetClient(api_key, api_version) - self.invalid_client = bayonet.BayonetClient(invalid_api_key, api_version) + self.client = bayonet.BayonetClient(api_key) + self.invalid_client = bayonet.BayonetClient(invalid_api_key) def test_should_validate_api_key(self): try: - self.invalid_client.feedback(params_feedback) + self.invalid_client.update_transaction(params_update_transaction) except bayonet.BayonetError as e: - self.assertEqual(e.reason_code, "11") + self.assertEqual(e.reason_code, 12) - def test_should_return_error_on_invalid_api_trans_code(self): - params_feedback['feedback_api_trans_code'] = 'xxx' + def test_should_return_error_on_invalid_bayonet_tracking_code(self): + params_update_transaction['bayonet_tracking_id'] = 'xxx' with self.assertRaises(bayonet.BayonetError): - self.client.feedback(params_feedback) + self.client.update_transaction(params_update_transaction) - def test_should_validate_api_trans_code(self): - params_feedback['feedback_api_trans_code'] = 'xxx' + def test_should_validate_bayonet_tracking_id(self): + params_update_transaction['bayonet_tracking_id'] = 'xxx' try: - self.client.feedback(params_feedback) + self.client.update_transaction(params_update_transaction) except bayonet.BayonetError as e: - self.assertEqual(e.reason_code, "87") + self.assertEqual(e.reason_code, 162) def test_should_return_success(self): - params_feedback['feedback_api_trans_code'] = feedback_api_trans_code - r = self.client.feedback(params_feedback) - self.assertEqual(r.reason_code, "00") + params_update_transaction['bayonet_tracking_id'] = bayonet_tracking_id + r = self.client.update_transaction(params_update_transaction) + self.assertEqual(r.reason_code, 0) class TestFeedbackHistorical(unittest.TestCase): def setUp(self): - self.client = bayonet.BayonetClient(api_key, api_version) - self.invalid_client = bayonet.BayonetClient(invalid_api_key, api_version) + self.client = bayonet.BayonetClient(api_key) + self.invalid_client = bayonet.BayonetClient(invalid_api_key) def test_should_validate_api_key(self): try: self.invalid_client.feedback_historical(params_feedback_historical) except bayonet.BayonetError as e: - self.assertEqual(e.reason_code, "11") - - def test_should_return_success_on_chargeback_feedback(self): - r = self.client.feedback_historical(params_chargeback_feedback) - self.assertEqual(r.reason_code, "00") + self.assertEqual(e.reason_code, 12) def test_should_return_success(self): r = self.client.feedback_historical(params_feedback_historical) - self.assertEqual(r.reason_code, "00") + self.assertEqual(r.reason_code, 0) - -class TestGetFingerprintData(unittest.TestCase): +class TestLists(unittest.TestCase): def setUp(self): - self.client = bayonet.BayonetClient(api_key, api_version) - self.invalid_client = bayonet.BayonetClient(invalid_api_key, api_version) - - def test_should_validate_fingerprint_token(self): + self.client = bayonet.BayonetClient(api_key) + self.invalid_client = bayonet.BayonetClient(invalid_api_key) + + def test_should_validate_api_key(self): try: - self.invalid_client.get_fingerprint_data(params_get_fingerprint_data) + self.invalid_client.blocklist_add(params_blocklist_valid) except bayonet.BayonetError as e: - self.assertEqual(e.status, "Error: Invalid value for bayonet_fingerprint_token") + self.assertEqual(e.reason_code, 12) + def test_should_validate_email_in_system(self): + try: + self.client.blocklist_add(params_blocklist_valid) + except bayonet.BayonetError as e: + self.assertEqual(e.reason_code, 152) + + def test_should_accept_email_when_adding_to_list(self): + try: + self.client.blocklist_add(params_blocklist_valid) + except: + self.assertEqual(e.reason_code, 0) if __name__ == "__main__": unittest.main()