diff --git a/arcsecond/__init__.py b/arcsecond/__init__.py index 1461fb1..219fb48 100644 --- a/arcsecond/__init__.py +++ b/arcsecond/__init__.py @@ -7,4 +7,4 @@ "ArcsecondConnectionError", "ArcsecondInvalidEndpointError"] -__version__ = '0.7.2' +__version__ = '0.7.3' diff --git a/arcsecond/api/endpoints/_base.py b/arcsecond/api/endpoints/_base.py index d8636e7..8f03f97 100644 --- a/arcsecond/api/endpoints/_base.py +++ b/arcsecond/api/endpoints/_base.py @@ -70,7 +70,7 @@ def _check_and_set_api_key(self, headers, url): if self.state.verbose: click.echo('Checking local API key... ', nl=False) - api_key = config_file_read_api_key(self.state.debug) + api_key = config_file_read_api_key(self.state.config_section()) if not api_key: raise ArcsecondError('Missing API key. You must login first: $ arcsecond login') @@ -81,7 +81,7 @@ def _check_and_set_api_key(self, headers, url): return headers def _check_organisation_membership_and_permission(self, method_name, organisation): - memberships = config_file_read_organisation_memberships(self.state.debug) + memberships = config_file_read_organisation_memberships(self.state.config_section()) if self.state.organisation not in memberships.keys(): raise ArcsecondError('No membership found for organisation {}'.format(organisation)) membership = memberships[self.state.organisation] diff --git a/arcsecond/api/main.py b/arcsecond/api/main.py index e9c178b..5d5136a 100644 --- a/arcsecond/api/main.py +++ b/arcsecond/api/main.py @@ -14,6 +14,8 @@ from arcsecond.config import (config_file_path, config_file_read_api_key, config_file_save_api_key, + config_file_read_username, + config_file_read_organisation_memberships, config_file_save_organisation_membership) from arcsecond.options import State @@ -81,8 +83,16 @@ def factory(endpoint_class, state, **kwargs): @set_api_factory class Arcsecond(object): @classmethod - def is_logged_in(cls, state=None): - return ArcsecondAPI.is_logged_in(state) + def is_logged_in(cls, state=None, **kwargs): + return ArcsecondAPI.is_logged_in(state, **kwargs) + + @classmethod + def username(cls, state=None, **kwargs): + return ArcsecondAPI.username(state, **kwargs) + + @classmethod + def memberships(cls, state=None, **kwargs): + return ArcsecondAPI.memberships(state, **kwargs) @classmethod def login(cls, username, password, subdomain, state=None): @@ -200,7 +210,7 @@ def delete(self, id_name_uuid, **headers): def _check_organisation_membership(cls, state, username, subdomain): if state.verbose: click.echo('Checking Membership of Organisation with subdomain "{}"...'.format(subdomain)) - profile, error = PersonalProfileAPIEndPoint(State(verbose=False, debug=state.debug)).read(username) + profile, error = PersonalProfileAPIEndPoint(state.make_new_silent()).read(username) if error: ArcsecondAPI._echo_error(state, error) else: @@ -209,7 +219,7 @@ def _check_organisation_membership(cls, state, username, subdomain): if state.verbose: click.echo('Membership confirmed. Role is "{}", stored in {}.' .format(memberships[subdomain], config_file_path())) - config_file_save_organisation_membership(subdomain, memberships[subdomain], state.debug) + config_file_save_organisation_membership(subdomain, memberships[subdomain], state.config_section()) else: if state.verbose: click.echo('Membership denied.') @@ -223,15 +233,25 @@ def _get_and_save_api_key(cls, state, username, auth_token): return ArcsecondAPI._echo_error(state, error) if result: api_key = result['api_key'] - config_file_save_api_key(api_key, username, state.debug) + config_file_save_api_key(api_key, username, state.config_section()) if state.verbose: click.echo('Successful API key retrieval and storage in {}. Enjoy.'.format(config_file_path())) return result @classmethod - def is_logged_in(cls, state=None): - state = get_api_state(state) - return config_file_read_api_key(debug=state.debug) is not None + def is_logged_in(cls, state=None, **kwargs): + state = get_api_state(state, **kwargs) + return config_file_read_api_key(section=state.config_section()) is not None + + @classmethod + def username(cls, state=None, **kwargs): + state = get_api_state(state, **kwargs) + return config_file_read_username(section=state.config_section()) or '' + + @classmethod + def memberships(cls, state=None, **kwargs): + state = get_api_state(state, **kwargs) + return config_file_read_organisation_memberships(section=state.config_section()) @classmethod def login(cls, username, password, subdomain, state=None): diff --git a/arcsecond/cli.py b/arcsecond/cli.py index 04c4ec1..772d213 100644 --- a/arcsecond/cli.py +++ b/arcsecond/cli.py @@ -56,7 +56,7 @@ def login(state, username, password, organisation=None): @pass_state def me(state): """Fetch your complete user profile.""" - username = config_file_read_username(state.debug) + username = config_file_read_username(state.config_section()) if not username: msg = 'Invalid/missing username: {}. Make sure to login first: $ arcsecond login'.format(username) raise ArcsecondError(msg) diff --git a/arcsecond/config.py b/arcsecond/config.py index 51f4dee..3c68318 100644 --- a/arcsecond/config.py +++ b/arcsecond/config.py @@ -11,19 +11,17 @@ def config_file_exists(): return os.path.exists(path) and os.path.isfile(path) -def config_file_is_valid(debug=False): +def config_file_is_valid(section='main'): if not config_file_exists(): return False config = ConfigParser() config.read(config_file_path()) - section = 'debug' if debug else 'main' return config[section].get('api_key') -def config_file_save_api_key(api_key, username, debug=False): +def config_file_save_api_key(api_key, username, section='main'): config = ConfigParser() config.read(config_file_path()) - section = 'debug' if debug else 'main' if section not in config.keys(): config.add_section(section) config.set(section, 'username', username) @@ -32,10 +30,9 @@ def config_file_save_api_key(api_key, username, debug=False): config.write(f) -def config_file_save_organisation_membership(subdomain, role, debug=False): +def config_file_save_organisation_membership(subdomain, role, section='main'): config = ConfigParser() config.read(config_file_path()) - section = 'debug' if debug else 'main' section += ':organisations' if section not in config.keys(): config.add_section(section) @@ -44,39 +41,37 @@ def config_file_save_organisation_membership(subdomain, role, debug=False): config.write(f) -def config_file_read_organisation_memberships(debug=False): +def config_file_read_organisation_memberships(section='main'): config = ConfigParser() config.read(config_file_path()) - section = 'debug' if debug else 'main' section += ':organisations' if section not in config.sections(): return {} return config[section] -def config_file_read_key(key, debug=False): +def config_file_read_key(key, section='main'): config = ConfigParser() config.read(config_file_path()) - section = 'debug' if debug else 'main' if section not in config.sections(): return None return config[section].get(key, None) -def config_file_read_api_key(debug=False): - return config_file_read_key('api_key', debug=debug) +def config_file_read_api_key(section='main'): + return config_file_read_key('api_key', section=section) -def config_file_read_username(debug=False): - return config_file_read_key('username', debug=debug) +def config_file_read_username(section='main'): + return config_file_read_key('username', section=section) -def config_file_clear_debug_session(): +def config_file_clear_section(section): config = ConfigParser() config.read(config_file_path()) - if 'debug' in config.sections(): - del config['debug'] - if 'debug:organisations' in config.sections(): - del config['debug:organisations'] + if section in config.sections(): + del config[section] + if section + ':organisations' in config.sections(): + del config[section + ':organisations'] with open(config_file_path(), 'w') as f: config.write(f) diff --git a/arcsecond/options.py b/arcsecond/options.py index b63352a..75e467f 100644 --- a/arcsecond/options.py +++ b/arcsecond/options.py @@ -9,6 +9,9 @@ def __init__(self, verbose=0, debug=False, open=None, organisation=None, is_usin self.organisation = organisation self.is_using_cli = is_using_cli + def config_section(self): + return 'debug' if self.debug else 'main' + def make_new_silent(self): return State(verbose=0, debug=self.debug, diff --git a/tests/test_arcsecond_root.py b/tests/test_arcsecond_root.py new file mode 100644 index 0000000..acdb5aa --- /dev/null +++ b/tests/test_arcsecond_root.py @@ -0,0 +1,23 @@ +from arcsecond import Arcsecond +from .utils import save_test_credentials, clear_test_credentials + + +def test_default_empty_state(): + clear_test_credentials() + assert Arcsecond.is_logged_in(debug=True) is False + assert Arcsecond.username(debug=True) == '' + assert Arcsecond.memberships(debug=True) == {} + + +def test_default_logged_in_state(): + save_test_credentials('cedric') + assert Arcsecond.is_logged_in(debug=True) is True + assert Arcsecond.username(debug=True) == 'cedric' + assert Arcsecond.memberships(debug=True) == {} + + +def test_default_logged_in_with_membership_state(): + save_test_credentials('cedric', {'saao': 'superadmin'}) + assert Arcsecond.is_logged_in(debug=True) is True + assert Arcsecond.username(debug=True) == 'cedric' + assert Arcsecond.memberships(debug=True) == {'saao': 'superadmin'} diff --git a/tests/test_datasets_organisations.py b/tests/test_datasets_organisations.py index 348fefd..90b3a69 100644 --- a/tests/test_datasets_organisations.py +++ b/tests/test_datasets_organisations.py @@ -4,7 +4,7 @@ from arcsecond import cli from arcsecond.api.error import ArcsecondError -from arcsecond.config import config_file_clear_debug_session +from arcsecond.config import config_file_clear_section from .utils import (register_successful_personal_login, register_successful_organisation_login, @@ -14,7 +14,7 @@ class DatasetsInOrganisationsTestCase(TestCase): def setUp(self): - config_file_clear_debug_session() + config_file_clear_section('debug') httpretty.enable() def tearDown(self): diff --git a/tests/utils.py b/tests/utils.py index 00cf45b..2bd5010 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,8 +1,12 @@ import json import httpretty -from arcsecond.api.constants import API_AUTH_PATH_LOGIN, ARCSECOND_API_URL_DEV + from arcsecond import cli +from arcsecond.api.constants import API_AUTH_PATH_LOGIN, ARCSECOND_API_URL_DEV +from arcsecond.config import (config_file_clear_section, + config_file_save_api_key, + config_file_save_organisation_membership) TEST_LOGIN_USERNAME = 'robot1' TEST_LOGIN_PASSWORD = 'robotpass' @@ -75,6 +79,18 @@ def register_successful_organisation_login(runner, subdomain, role): input=TEST_LOGIN_USERNAME + '\n' + TEST_LOGIN_PASSWORD) +def save_test_credentials(username, memberships=None): + if memberships is None: + memberships = dict() + config_file_save_api_key(TEST_API_KEY, username, section='debug') + for k, v in memberships.items(): + config_file_save_organisation_membership(k, v, 'debug') + + +def clear_test_credentials(): + config_file_clear_section('debug') + + def mock_url_path(method, path, body='', query='', status=200): path = path + '/' if path[-1] != '/' else path httpretty.register_uri(method, ARCSECOND_API_URL_DEV + path + query, status=status, body=body)