diff --git a/tests/functional/test_api_v2.py b/tests/functional/test_api_v2.py index 4fbf81d..7af9430 100644 --- a/tests/functional/test_api_v2.py +++ b/tests/functional/test_api_v2.py @@ -85,7 +85,7 @@ def test_api_params(self, wykop_api_v2): } body = json.dumps(body_dict) - api_params = 'page/2/appkey/123456app/format/json' + api_params = 'appkey/123456app/format/json/page/2' url = '{protocol}://{domain}/{rtype}/{rmethod}/{api_params}'.format( protocol=wykop_api_v2._protocol, domain=wykop_api_v2._domain, diff --git a/tests/unit/api/v1/test_v1_clients.py b/tests/unit/api/v1/test_v1_clients.py index 199978c..67a4dc2 100644 --- a/tests/unit/api/v1/test_v1_clients.py +++ b/tests/unit/api/v1/test_v1_clients.py @@ -1,3 +1,5 @@ +import base64 +import json import mock import pytest @@ -392,6 +394,63 @@ def test_no_parser( assert result == response +class TestWykopAPIGetConnectUrl(object): + + def test_empty_redirect(self, wykop_api): + redirect_url = '' + + result = wykop_api.get_connect_url(redirect_url) + + assert result == ( + '{0}://{1}/user/connect/appkey,sentinel.appkey,format,sentinel.' + 'format,output,sentinel.output,redirect,,secure,' + '7442ad1ab40db3ae567690b838c6879d,userkey,' + ).format( + wykop_api._protocol, + wykop_api._domain, + ) + + def test_with_redirect(self, wykop_api): + redirect_url = 'test.com' + + result = wykop_api.get_connect_url(redirect_url) + + assert result == ( + '{0}://{1}/user/connect/appkey,sentinel.appkey,format,sentinel.' + 'format,output,sentinel.output,redirect,dGVzdC5jb20%3D,secure,' + '56915610d9335cb4300b1d8b937f9495,userkey,' + ).format( + wykop_api._protocol, + wykop_api._domain, + ) + + +class TestWykopAPIGetConnectData(object): + + @pytest.fixture + def connect_data_factory(self): + def get_connect_data(appkey, login, token): + data = { + 'appkey': appkey, + 'login': login, + 'token': token, + } + data_str = json.dumps(data) + data_bytes = data_str.encode() + return base64.encodestring(data_bytes) + return get_connect_data + + def test_decoded(self, wykop_api, connect_data_factory): + appkey = 'appkey' + login = 'login' + token = 'token' + data_bytes_encoded = connect_data_factory(appkey, login, token) + + result = wykop_api.get_connect_data(data_bytes_encoded) + + assert result == (appkey, login, token) + + class TestRotatingKeysWykopAPIRequest(object): @mock.patch.object(WykopAPI, 'request') diff --git a/tests/unit/api/v2/test_v2_clients.py b/tests/unit/api/v2/test_v2_clients.py index f27145d..976fbcf 100644 --- a/tests/unit/api/v2/test_v2_clients.py +++ b/tests/unit/api/v2/test_v2_clients.py @@ -1,5 +1,8 @@ +import base64 +import json from types import GeneratorType import mock +import pytest from wykop.api.v2.clients import WykopAPIv2 @@ -35,10 +38,10 @@ def test_mapped(self, wykop_api_v2): assert type(result) == GeneratorType assert tuple(result) == ( - 'test1', '1', 'appkey', 'sentinel.appkey', 'format', 'sentinel.format', 'output', 'sentinel.output', + 'test1', '1', ) @@ -140,3 +143,72 @@ def test_api_params(self, mocked_get_path, wykop_api_v2): wykop_api_v2._domain, path, ) + + +class TestWykopAPIv2GetConnectUrl(object): + + def test_no_redirect(self, wykop_api_v2): + result = wykop_api_v2.get_connect_url() + + assert result == ( + '{0}://{1}/login/connect/appkey/sentinel.appkey/' + 'format/sentinel.format/output/sentinel.output/' + 'secure/fac51ab497520eb2d672129c5b69dc72' + ).format( + wykop_api_v2._protocol, + wykop_api_v2._domain, + ) + + def test_empty_redirect(self, wykop_api_v2): + redirect_url = '' + + result = wykop_api_v2.get_connect_url(redirect_url) + + assert result == ( + '{0}://{1}/login/connect/appkey/sentinel.appkey/' + 'format/sentinel.format/output/sentinel.output/' + 'secure/7442ad1ab40db3ae567690b838c6879d' + ).format( + wykop_api_v2._protocol, + wykop_api_v2._domain, + ) + + def test_with_redirect(self, wykop_api_v2): + redirect_url = 'test.com' + + result = wykop_api_v2.get_connect_url(redirect_url) + + assert result == ( + '{0}://{1}/login/connect/appkey/sentinel.appkey/' + 'format/sentinel.format/output/sentinel.output/' + 'redirect/dGVzdC5jb20%3D/secure/56915610d9335cb4300b1d8b937f9495' + ).format( + wykop_api_v2._protocol, + wykop_api_v2._domain, + ) + + +class TestWykopAPIGetConnectData(object): + + @pytest.fixture + def connect_data_factory(self): + def get_connect_data(appkey, login, token): + data = { + 'appkey': appkey, + 'login': login, + 'token': token, + } + data_str = json.dumps(data) + data_bytes = data_str.encode() + return base64.encodestring(data_bytes) + return get_connect_data + + def test_decoded(self, wykop_api_v2, connect_data_factory): + appkey = 'appkey' + login = 'login' + token = 'token' + data_bytes_encoded = connect_data_factory(appkey, login, token) + + result = wykop_api_v2.get_connect_data(data_bytes_encoded) + + assert result == (appkey, login, token) diff --git a/tox.ini b/tox.ini index 14b4927..b64d982 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py34 +envlist = py27,py36 [testenv] commands = python setup.py test \ No newline at end of file diff --git a/wykop/api/clients.py b/wykop/api/clients.py index e59e3c6..1402770 100644 --- a/wykop/api/clients.py +++ b/wykop/api/clients.py @@ -110,3 +110,33 @@ def get_headers(self, url, **post_params): 'apisign': apisign, 'User-Agent': user_agent, } + + def get_connect_api_params(self, redirect_url=None): + """ + Gets request api parameters for wykop connect. + """ + apisign = self.get_api_sign(redirect_url) + + api_params = { + 'secure': apisign, + } + + if redirect_url is not None: + redirect_url_bytes = force_bytes(redirect_url) + redirect_url_encoded = quote_plus( + base64.b64encode(redirect_url_bytes)) + api_params.update({ + 'redirect': redirect_url_encoded, + }) + + return api_params + + def get_connect_data(self, data, parser=default_parser): + """ + Gets decoded data from wykop connect. + """ + data_bytes = force_bytes(data) + decoded = base64.decodestring(data_bytes) + decoded_str = force_text(decoded) + parsed = parser.parse(decoded_str) + return parsed['appkey'], parsed['login'], parsed['token'] diff --git a/wykop/api/v1/clients.py b/wykop/api/v1/clients.py index f8093c8..38d8519 100644 --- a/wykop/api/v1/clients.py +++ b/wykop/api/v1/clients.py @@ -133,18 +133,6 @@ def user_login(self, login, accountkey=None, password=None): # Connect - def get_connect_api_params(self, redirect_url): - """ - Gets request api parameters for wykop connect. - """ - redirect_url_encoded = quote_plus(base64.b64encode(redirect_url)) - apisign = self.get_api_sign(redirect_url) - - return { - 'redirect': redirect_url_encoded, - 'secure': apisign, - } - def get_connect_url(self, redirect_url): """ Gets url for wykop connect. @@ -153,14 +141,6 @@ def get_connect_url(self, redirect_url): return self.construct_url('user', 'connect', **api_params) - def get_connect_data(self, data, parser=default_parser): - """ - Gets decoded data from wykop connect. - """ - decoded = base64.decodestring(data) - parsed = parser.parse(decoded) - return parsed['appkey'], parsed['login'], parsed['token'] - # Comments @login_required diff --git a/wykop/api/v2/clients.py b/wykop/api/v2/clients.py index 4a6f373..ad1801a 100644 --- a/wykop/api/v2/clients.py +++ b/wykop/api/v2/clients.py @@ -1,7 +1,8 @@ +import base64 import logging from collections import OrderedDict -from six.moves.urllib.parse import urlunparse +from six.moves.urllib.parse import urlunparse, quote_plus from wykop.api.clients import BaseWykopAPI from wykop.api.decorators import login_required @@ -83,15 +84,12 @@ def get_api_params(self, **api_params): """ Gets request method parameters. """ - default_params = self.get_default_api_params() + params = self.get_default_api_params() + params.update(api_params) # sort - params = OrderedDict(api_params) - params.update([ - (k, default_params[k]) - for k in sorted(default_params, key=default_params.get) - ]) + params_ordered = OrderedDict(sorted(params.items())) # map all params to string - for key, value in params.items(): + for key, value in params_ordered.items(): if not value: continue yield str(key) @@ -127,6 +125,16 @@ def user_login(self, login, accountkey=None, password=None): return self.request('login', post_params=post_params) + # Connect + + def get_connect_url(self, redirect_url=None): + """ + Gets url for wykop connect. + """ + api_params = self.get_connect_api_params(redirect_url) + + return self.construct_url('login', 'connect', **api_params) + # entries def get_entry(self, entry_id):