From 5fe452c49e8345894233fbe6141fd8eca7b5106a Mon Sep 17 00:00:00 2001 From: Pierre Geier Date: Thu, 16 Feb 2017 14:39:22 +0100 Subject: [PATCH 1/5] Make this compatible with plentymarkets Plentymarkets uses CamelCase for token responses See here: https://developers.plentymarkets.com/rest-doc/introduction --- .../compliance_fixes/__init__.py | 1 + .../compliance_fixes/plentymarkets.py | 35 +++++++++++++++++ tests/test_compliance_fixes.py | 39 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 requests_oauthlib/compliance_fixes/plentymarkets.py diff --git a/requests_oauthlib/compliance_fixes/__init__.py b/requests_oauthlib/compliance_fixes/__init__.py index 65e49c15..35e8e1ca 100644 --- a/requests_oauthlib/compliance_fixes/__init__.py +++ b/requests_oauthlib/compliance_fixes/__init__.py @@ -6,3 +6,4 @@ from .slack import slack_compliance_fix from .mailchimp import mailchimp_compliance_fix from .weibo import weibo_compliance_fix +from .plentymarkets import plentymarkets_compliance_fix \ No newline at end of file diff --git a/requests_oauthlib/compliance_fixes/plentymarkets.py b/requests_oauthlib/compliance_fixes/plentymarkets.py new file mode 100644 index 00000000..f63f5c84 --- /dev/null +++ b/requests_oauthlib/compliance_fixes/plentymarkets.py @@ -0,0 +1,35 @@ +from json import dumps, loads + +from oauthlib.common import to_unicode + + +def plentymarkets_compliance_fix(session): + + def _compliance_fix(r): + + # Plenty returns the Token in CamelCase instead with _ + if 'application/json' in r.headers.get('content-type', {}) and r.status_code == 200: + token = loads(r.text) + else: + return r + + expires = token.pop('expiresIn') + if expires is not None: + token['expires_in'] = expires + + access_token = token.pop('accessToken') + if access_token is not None: + token['access_token'] = access_token + + refresh_token = token.pop('refreshToken') + if refresh_token is not None: + token['refresh_token'] = refresh_token + + token['token_type'] = 'Bearer' + del token['tokenType'] + + r._content = to_unicode(dumps(token)).encode('UTF-8') + return r + + session.register_compliance_hook('access_token_response', _compliance_fix) + return session diff --git a/tests/test_compliance_fixes.py b/tests/test_compliance_fixes.py index 0184d33b..7304b31a 100644 --- a/tests/test_compliance_fixes.py +++ b/tests/test_compliance_fixes.py @@ -20,6 +20,7 @@ from requests_oauthlib.compliance_fixes import mailchimp_compliance_fix from requests_oauthlib.compliance_fixes import weibo_compliance_fix from requests_oauthlib.compliance_fixes import slack_compliance_fix +from requests_oauthlib.compliance_fixes import plentymarkets_compliance_fix class FacebookComplianceFixTest(TestCase): @@ -275,3 +276,41 @@ def test_protected_request_override_token_url(self): query = parse_qs(urlparse(url).query) self.assertEqual(query["token"], ["different-token"]) self.assertIsNone(response.request.body) + + +class PlentymarketsComplianceFixTest(TestCase): + + def setUp(self): + mocker = requests_mock.Mocker() + mocker.post( + "https://shop.plentymarkets-cloud02.com", + json= + { + "accessToken": "ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61", + "tokenType": "Bearer", + "expiresIn": 86400, + "refreshToken": "iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX" + }, + headers={"Content-Type": "application/json"} + ) + mocker.start() + self.addCleanup(mocker.stop) + + plentymarkets = OAuth2Session('foo', redirect_uri='https://i.b') + self.session = plentymarkets_compliance_fix(plentymarkets) + + def test_fetch_access_token(self): + token = self.session.fetch_token( + "https://shop.plentymarkets-cloud02.com", + authorization_response='https://i.b/?code=hello', + ) + + approx_expires_at = time.time() + 3600 + actual_expires_at = token.pop('expires_at') + self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2) + + self.assertEqual(token, {u'access_token': u'ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61', + u'expires_in': 86400, + u'expires_at': 1487337993.088303, + u'token_type': u'Bearer', + u'refresh_token': u'iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX'}) From b0a98d7230d612c4e4b03f251b9a7a67436038bb Mon Sep 17 00:00:00 2001 From: Pierre Geier Date: Thu, 16 Feb 2017 15:03:10 +0100 Subject: [PATCH 2/5] token dictionary remains untouched token dict in plentymarkets.py remains untouched fixed tests for the plentymarkets compliance_fixes --- requests_oauthlib/compliance_fixes/plentymarkets.py | 13 +++++++------ tests/test_compliance_fixes.py | 3 +-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/requests_oauthlib/compliance_fixes/plentymarkets.py b/requests_oauthlib/compliance_fixes/plentymarkets.py index f63f5c84..f0fd9585 100644 --- a/requests_oauthlib/compliance_fixes/plentymarkets.py +++ b/requests_oauthlib/compliance_fixes/plentymarkets.py @@ -13,22 +13,23 @@ def _compliance_fix(r): else: return r + fixed_token = {} + expires = token.pop('expiresIn') if expires is not None: - token['expires_in'] = expires + fixed_token['expires_in'] = expires access_token = token.pop('accessToken') if access_token is not None: - token['access_token'] = access_token + fixed_token['access_token'] = access_token refresh_token = token.pop('refreshToken') if refresh_token is not None: - token['refresh_token'] = refresh_token + fixed_token['refresh_token'] = refresh_token - token['token_type'] = 'Bearer' - del token['tokenType'] + fixed_token['token_type'] = 'Bearer' - r._content = to_unicode(dumps(token)).encode('UTF-8') + r._content = to_unicode(dumps(fixed_token)).encode('UTF-8') return r session.register_compliance_hook('access_token_response', _compliance_fix) diff --git a/tests/test_compliance_fixes.py b/tests/test_compliance_fixes.py index 7304b31a..8e9ee2df 100644 --- a/tests/test_compliance_fixes.py +++ b/tests/test_compliance_fixes.py @@ -305,12 +305,11 @@ def test_fetch_access_token(self): authorization_response='https://i.b/?code=hello', ) - approx_expires_at = time.time() + 3600 + approx_expires_at = time.time() + 86400 actual_expires_at = token.pop('expires_at') self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2) self.assertEqual(token, {u'access_token': u'ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61', u'expires_in': 86400, - u'expires_at': 1487337993.088303, u'token_type': u'Bearer', u'refresh_token': u'iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX'}) From 32e43d7c331883327f814939febbcbfaa7731bb4 Mon Sep 17 00:00:00 2001 From: Pierre Geier Date: Thu, 16 Feb 2017 15:16:31 +0100 Subject: [PATCH 3/5] Plenty compliance fix: cleanup More generic approch to convert the Token to snake case. --- .../compliance_fixes/plentymarkets.py | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/requests_oauthlib/compliance_fixes/plentymarkets.py b/requests_oauthlib/compliance_fixes/plentymarkets.py index f0fd9585..cd3d605a 100644 --- a/requests_oauthlib/compliance_fixes/plentymarkets.py +++ b/requests_oauthlib/compliance_fixes/plentymarkets.py @@ -1,10 +1,14 @@ from json import dumps, loads +import re from oauthlib.common import to_unicode def plentymarkets_compliance_fix(session): + def _to_snake_case(n): + return re.sub('(.)([A-Z][a-z]+)', r'\1_\2', n).lower() + def _compliance_fix(r): # Plenty returns the Token in CamelCase instead with _ @@ -14,20 +18,8 @@ def _compliance_fix(r): return r fixed_token = {} - - expires = token.pop('expiresIn') - if expires is not None: - fixed_token['expires_in'] = expires - - access_token = token.pop('accessToken') - if access_token is not None: - fixed_token['access_token'] = access_token - - refresh_token = token.pop('refreshToken') - if refresh_token is not None: - fixed_token['refresh_token'] = refresh_token - - fixed_token['token_type'] = 'Bearer' + for k, v in token.items(): + fixed_token[_to_snake_case(k)] = v r._content = to_unicode(dumps(fixed_token)).encode('UTF-8') return r From bb18ec0b656d87e23a0a7b13e7e089c42878332c Mon Sep 17 00:00:00 2001 From: Pierre Geier Date: Thu, 16 Feb 2017 16:20:35 +0100 Subject: [PATCH 4/5] Typo in compliance fixes for plentymarkets fixed --- requests_oauthlib/compliance_fixes/plentymarkets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requests_oauthlib/compliance_fixes/plentymarkets.py b/requests_oauthlib/compliance_fixes/plentymarkets.py index cd3d605a..1b8a236f 100644 --- a/requests_oauthlib/compliance_fixes/plentymarkets.py +++ b/requests_oauthlib/compliance_fixes/plentymarkets.py @@ -10,8 +10,7 @@ def _to_snake_case(n): return re.sub('(.)([A-Z][a-z]+)', r'\1_\2', n).lower() def _compliance_fix(r): - - # Plenty returns the Token in CamelCase instead with _ + # Plenty returns the Token in CamelCase instead of _ if 'application/json' in r.headers.get('content-type', {}) and r.status_code == 200: token = loads(r.text) else: From 18498849f42dcf0e745454a73865a2d1ff6cb7f4 Mon Sep 17 00:00:00 2001 From: Pierre Geier Date: Thu, 16 Feb 2017 16:27:23 +0100 Subject: [PATCH 5/5] code cleanup in compliance_fixes/__init__.py Removed double-space and added newline --- requests_oauthlib/compliance_fixes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests_oauthlib/compliance_fixes/__init__.py b/requests_oauthlib/compliance_fixes/__init__.py index 35e8e1ca..1084f63d 100644 --- a/requests_oauthlib/compliance_fixes/__init__.py +++ b/requests_oauthlib/compliance_fixes/__init__.py @@ -6,4 +6,4 @@ from .slack import slack_compliance_fix from .mailchimp import mailchimp_compliance_fix from .weibo import weibo_compliance_fix -from .plentymarkets import plentymarkets_compliance_fix \ No newline at end of file +from .plentymarkets import plentymarkets_compliance_fix