From 67d530e4cfdc6086a42ebbd985c744ed4a1ed56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81dric=20Foellmi?= Date: Sun, 31 Mar 2024 18:38:51 +0530 Subject: [PATCH] Validating the membership of organisation remotely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Foellmi --- arcsecond/api/constants.py | 1 + arcsecond/api/endpoint.py | 10 ++++++---- arcsecond/api/main.py | 28 ++++++++++++++-------------- arcsecond/cli.py | 16 +++++----------- arcsecond/uploader/context.py | 21 +++++++-------------- 5 files changed, 33 insertions(+), 43 deletions(-) diff --git a/arcsecond/api/constants.py b/arcsecond/api/constants.py index bfb20d2..8c1bcca 100644 --- a/arcsecond/api/constants.py +++ b/arcsecond/api/constants.py @@ -5,3 +5,4 @@ ARCSECOND_WWW_URL_PROD = 'https://www.arcsecond.io' API_AUTH_PATH_VERIFY = '/auth/key/verify/' +API_AUTH_PATH_VERIFY_PORTAL = '/auth/key/verify-organisation/' diff --git a/arcsecond/api/endpoint.py b/arcsecond/api/endpoint.py index 2b6a2e5..a640bc0 100644 --- a/arcsecond/api/endpoint.py +++ b/arcsecond/api/endpoint.py @@ -4,7 +4,7 @@ import requests from arcsecond.api.config import ArcsecondConfig -from arcsecond.api.constants import API_AUTH_PATH_VERIFY +from arcsecond.api.constants import API_AUTH_PATH_VERIFY, API_AUTH_PATH_VERIFY_PORTAL from arcsecond.errors import ArcsecondError SAFE_METHODS = ['GET', 'OPTIONS'] @@ -23,12 +23,14 @@ def path(self): return self.__path def _get_base_url(self): - return self.__config.api_server + url = self.__config.api_server + if not url.endswith('/'): url += '/' + return url def _build_url(self, *args, **filters): fragments = [f for f in [self.__subdomain, ] + list(args) + [self.__subresource, ] if f and len(f) > 0] url = self._get_base_url() + '/'.join(fragments) - if url[-1] != '/': url += '/' + if not url.endswith('/'): url += '/' query = '?' + urlencode(filters) if len(filters) > 0 else '' return url + query @@ -86,7 +88,7 @@ def _perform_request(self, url, method_name, json=None, data=None, headers=None) def _check_and_set_auth_key(self, headers, url): # No token header for login and register - if API_AUTH_PATH_VERIFY in url or 'Authorization' in headers.keys(): + if API_AUTH_PATH_VERIFY in url or API_AUTH_PATH_VERIFY_PORTAL in url or 'Authorization' in headers.keys(): return headers if self.__config.verbose: diff --git a/arcsecond/api/main.py b/arcsecond/api/main.py index 17b7ebc..11a0948 100644 --- a/arcsecond/api/main.py +++ b/arcsecond/api/main.py @@ -14,24 +14,24 @@ def __init__(self, config: ArcsecondConfig, subdomain: str = ''): self.config = config self.subdomain = subdomain - self.profiles = ArcsecondAPIEndpoint(self.config, '/profiles', self.subdomain) + self.profiles = ArcsecondAPIEndpoint(self.config, 'profiles', self.subdomain) - self.sharedkeys = ArcsecondAPIEndpoint(self.config, '/profiles', subresource='sharedkeys') - self.private_observingsites = ArcsecondAPIEndpoint(self.config, '/profiles', subresource='observingsites') - self.private_telescopes = ArcsecondAPIEndpoint(self.config, '/profiles', subresource='telescopes') + self.sharedkeys = ArcsecondAPIEndpoint(self.config, 'profiles', subresource='sharedkeys') + self.private_observingsites = ArcsecondAPIEndpoint(self.config, 'profiles', subresource='observingsites') + self.private_telescopes = ArcsecondAPIEndpoint(self.config, 'profiles', subresource='telescopes') - self.organisations = ArcsecondAPIEndpoint(self.config, '/organisations') # never subdomain here - self.members = ArcsecondAPIEndpoint(self.config, '/members', self.subdomain) + self.organisations = ArcsecondAPIEndpoint(self.config, 'organisations') # never subdomain here + self.members = ArcsecondAPIEndpoint(self.config, 'members', self.subdomain) - self.observingsites = ArcsecondAPIEndpoint(self.config, '/observingsites', self.subdomain) - self.telescopes = ArcsecondAPIEndpoint(self.config, '/telescopes', self.subdomain) - self.nightlogs = ArcsecondAPIEndpoint(self.config, '/nightlogs', self.subdomain) - self.observations = ArcsecondAPIEndpoint(self.config, '/observations', self.subdomain) - self.calibrations = ArcsecondAPIEndpoint(self.config, '/calibrations', self.subdomain) + self.observingsites = ArcsecondAPIEndpoint(self.config, 'observingsites', self.subdomain) + self.telescopes = ArcsecondAPIEndpoint(self.config, 'telescopes', self.subdomain) + self.nightlogs = ArcsecondAPIEndpoint(self.config, 'nightlogs', self.subdomain) + self.observations = ArcsecondAPIEndpoint(self.config, 'observations', self.subdomain) + self.calibrations = ArcsecondAPIEndpoint(self.config, 'calibrations', self.subdomain) - self.datapackages = ArcsecondAPIEndpoint(self.config, '/datapackages', self.subdomain) - self.datasets = ArcsecondAPIEndpoint(self.config, '/datasets', self.subdomain) - self.datafiles = ArcsecondAPIEndpoint(self.config, '/datafiles', self.subdomain) + self.datapackages = ArcsecondAPIEndpoint(self.config, 'datapackages', self.subdomain) + self.datasets = ArcsecondAPIEndpoint(self.config, 'datasets', self.subdomain) + self.datafiles = ArcsecondAPIEndpoint(self.config, 'datafiles', self.subdomain) def login(self, username, access_key=None, upload_key=None): assert access_key or upload_key diff --git a/arcsecond/cli.py b/arcsecond/cli.py index b56b24a..0f097ad 100644 --- a/arcsecond/cli.py +++ b/arcsecond/cli.py @@ -4,7 +4,6 @@ from . import __version__ from .api import ArcsecondAPI, ArcsecondConfig -from .errors import ArcsecondError from .options import State, basic_options from .uploader.context import Context from .uploader.errors import ArcsecondError @@ -36,13 +35,13 @@ def version(): @main.command(help='Login to your Arcsecond account.') @click.option('--username', required=True, nargs=1, prompt=True, help='Account username (without @). Primary email address is also allowed.') -@click.option('--access_key', required=False, nargs=1, prompt=True, +@click.option('--type', required=True, type=click.Choice(['access', 'upload'], case_sensitive=False), prompt=True, help='Your access key (a.k.a. API key). Visit your settings page to copy and paste it here. One of Access or Upload key must be provided.') -@click.option('--upload_key', required=False, nargs=1, prompt=True, +@click.option('--key', required=True, nargs=1, prompt=True, help='Your upload key. Visit your settings page to copy and paste it here. One of Access or Upload key must be provided.') @basic_options @pass_state -def login(state, username, access_key, upload_key): +def login(state, username, type, key): """Login to your personal Arcsecond.io account. You must provide either your Access Key, or your Upload Key. @@ -56,14 +55,9 @@ def login(state, username, access_key, upload_key): Beware that the Key you provide will be stored locally on the file: ~/.config/arcsecond/config.ini """ - if not access_key and not upload_key: - raise ArcsecondError('You must provide at least one of Access or Upload key.') - - if access_key and upload_key: - raise ArcsecondError('You must provide only one of Access or Upload key.') - + key_name = 'access_key' if type == 'access' else 'upload_key' config = ArcsecondConfig(state) - _, error = ArcsecondAPI(config).login(username, access_key=access_key, upload_key=upload_key) + _, error = ArcsecondAPI(config).login(username, **{key_name: key}) if error: click.echo(str(error)) else: diff --git a/arcsecond/uploader/context.py b/arcsecond/uploader/context.py index 0a21401..9c5e872 100644 --- a/arcsecond/uploader/context.py +++ b/arcsecond/uploader/context.py @@ -2,7 +2,8 @@ import click -from arcsecond import ArcsecondAPI, ArcsecondConfig +from arcsecond.api.constants import API_AUTH_PATH_VERIFY_PORTAL +from arcsecond import ArcsecondAPI, ArcsecondConfig, ArcsecondAPIEndpoint from .errors import ( UnknownOrganisationError, InvalidAstronomerError, @@ -71,8 +72,11 @@ def _validate_remote_organisation(self): raise UnknownOrganisationError(self._subdomain, str(error)) def _validate_astronomer_role_in_remote_organisation(self): - role = self._config.read_key(self._subdomain) - if not role or role not in ['member', 'admin', 'superadmin']: + endpoint = ArcsecondAPIEndpoint(self.config, API_AUTH_PATH_VERIFY_PORTAL) + result, error = endpoint.create({'username': self._config.username, + 'key': self._config.access_key or self._config.upload_key, + 'organisation': self._subdomain}) + if error: raise InvalidOrgMembershipError(self._subdomain) def update_dataset(self, dataset: dict): @@ -94,14 +98,3 @@ def dataset_name(self): @property def organisation_subdomain(self): return self._organisation.get('subdomain', '') if self._organisation else '' - - # def __print_organisation_telescopes(org_subdomain: str, api: str = 'main'): - # click.echo(f" • Here is a list of existing telescopes for organisation '{org_subdomain}':") - # kwargs = build_endpoint_kwargs(api, org_subdomain) - # telescope_list, error = ArcsecondAPI.telescopes(**kwargs).list() - # for telescope in telescope_list: - # s = f" 🔭 {telescope['name']}" - # if telescope.get('alias', ''): - # s += f" a.k.a. {telescope['alias']}" - # s += f" ({telescope['uuid']})" - # click.echo(s)