Skip to content

Commit

Permalink
Validating the membership of organisation remotely
Browse files Browse the repository at this point in the history
Signed-off-by: Cédric Foellmi <cedric@onekiloparsec.dev>
  • Loading branch information
onekiloparsec committed Mar 31, 2024
1 parent 75e04c6 commit 67d530e
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 43 deletions.
1 change: 1 addition & 0 deletions arcsecond/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/'
10 changes: 6 additions & 4 deletions arcsecond/api/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand All @@ -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

Expand Down Expand Up @@ -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:
Expand Down
28 changes: 14 additions & 14 deletions arcsecond/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 5 additions & 11 deletions arcsecond/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down
21 changes: 7 additions & 14 deletions arcsecond/uploader/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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):
Expand All @@ -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)

0 comments on commit 67d530e

Please sign in to comment.