Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move API endpoints from the config file to the code #118

Merged
merged 7 commits into from
May 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions mcmd/client/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from urllib.parse import urljoin, quote

from mcmd.config import config


def endpoint(func):
def wrapper(*args, **kwargs):
return urljoin(config.get('host', 'selected'), quote(func(*args, **kwargs)))

return wrapper


@endpoint
def rest1(path: str):
return urljoin('api/v1/', path)


@endpoint
def rest2(path: str):
return urljoin('api/v2/', path)


@endpoint
def login():
return 'api/v1/login/'


@endpoint
def group():
return 'api/plugin/security/group/'


@endpoint
def member(group_name):
return 'api/plugin/security/group/{}/member/'.format(group_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

group_name should be encoded (something like https://stackoverflow.com/a/6431284)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tommydeboer group name should still be encoded?



@endpoint
def import_():
return 'plugin/importwizard/importFile/'


@endpoint
def import_by_url():
return 'plugin/importwizard/importByUrl/'


@endpoint
def permissions():
return 'menu/admin/permissionmanager/update/'


@endpoint
def rls():
return 'menu/admin/permissionmanager/update/entityclass/rls'


@endpoint
def add_theme():
return 'plugin/thememanager/add-bootstrap-theme'


@endpoint
def set_theme():
return 'plugin/thememanager/set-bootstrap-theme'


@endpoint
def logo():
return 'plugin/menumanager/upload-logo'
13 changes: 8 additions & 5 deletions mcmd/client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"""

import json
from urllib.parse import urljoin

import requests
from requests import HTTPError

from mcmd import io
from mcmd.client import api
from mcmd.config import config
from mcmd.utils.errors import McmdError
from mcmd.utils.errors import McmdError, MolgenisOfflineError

_username = None
_password = None
Expand Down Expand Up @@ -40,7 +40,10 @@ def check_token():
return

try:
response = requests.get(urljoin(config.api('rest2'), 'sys_sec_Token?q=token=={}'.format(_token)),
response = requests.get(api.rest2('sys_sec_Token'),
params={
'q': 'token=={}'.format(_token)
},
headers={'Content-Type': 'application/json', 'x-molgenis-token': _token})
response.raise_for_status()
except HTTPError as e:
Expand All @@ -49,7 +52,7 @@ def check_token():
else:
raise McmdError(str(e))
except requests.exceptions.ConnectionError:
raise McmdError("Can't connect to {}".format(config.url()))
raise MolgenisOfflineError()


def _login():
Expand All @@ -61,7 +64,7 @@ def _login():

try:
io.debug('Logging in as user {}'.format(_username))
response = requests.post(config.api('login'),
response = requests.post(api.login(),
headers={'Content-Type': 'application/json'},
data=json.dumps({"username": _username, "password": _password}))
response.raise_for_status()
Expand Down
46 changes: 18 additions & 28 deletions mcmd/client/molgenis_client.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
import json
from urllib.parse import urljoin

import requests

from mcmd.client import auth
from mcmd.client.request_handler import request
from mcmd.config import config


@request()
def get(url):
@request
def get(url, params=None):
return requests.get(url,
params=params,
headers=_get_default_headers())


@request()
def post(url, data):
return requests.post(url,
headers=_get_default_headers(),
data=json.dumps(data))
@request
def post(url, data=None, params=None):
kwargs = {'headers': _get_default_headers()}
if data:
kwargs['data'] = json.dumps(data)
if params:
kwargs['params'] = params

return requests.post(url, **kwargs)


@request()
@request
def post_file(url, file_path, params):
return requests.post(url,
headers={'x-molgenis-token': auth.get_token()},
files={'file': open(file_path, 'rb')},
params=params)


@request()
@request
def post_files(files, url):
return requests.post(url,
headers={'x-molgenis-token': auth.get_token()},
files=files)


@request()
@request
def post_form(url, data):
return requests.post(url,
headers={
Expand All @@ -45,39 +48,26 @@ def post_form(url, data):
data=data)


@request()
@request
def delete(url):
return requests.delete(url,
headers=_get_default_headers())


@request()
@request
def delete_data(url, data):
return requests.delete(url,
headers=_get_default_headers(),
data=json.dumps({"entityIds": data}))


@request()
@request
def put(url, data):
return requests.put(url=url,
headers=_get_default_headers(),
data=data)


@request()
def import_by_url(params):
return requests.post(config.api('import_url'),
headers=_get_default_headers(),
params=params)


@request(login=False)
def get_version():
return requests.get(urljoin(config.api('rest2'), 'version'),
headers={'Content-Type': 'application/json'})


def _get_default_headers():
headers = {'Content-Type': 'application/json',
'x-molgenis-token': auth.get_token()}
Expand Down
44 changes: 19 additions & 25 deletions mcmd/client/request_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,31 @@
import requests

from mcmd.client import auth
from mcmd.config import config
from mcmd.utils.errors import McmdError
from mcmd.utils.errors import McmdError, MolgenisOfflineError


def request(login=True):
def request(func):
"""Request decorator."""

def decorator(func):

def handle_request(*args, **kwargs):
if login:
auth.check_token()

response = str()
try:
response = func(*args, **kwargs)
response.raise_for_status()
return response
except requests.HTTPError as e:
if _is_json(response):
_handle_json_error(response.json())
else:
raise McmdError(str(e))
except requests.exceptions.ConnectionError:
raise McmdError("Can't connect to {}".format(config.url()))
except requests.RequestException as e:
def handle_request(*args, **kwargs):
auth.check_token()

response = str()
try:
response = func(*args, **kwargs)
response.raise_for_status()
return response
except requests.HTTPError as e:
if _is_json(response):
_handle_json_error(response.json())
else:
raise McmdError(str(e))
except requests.exceptions.ConnectionError:
raise MolgenisOfflineError()
except requests.RequestException as e:
raise McmdError(str(e))

return handle_request

return decorator
return handle_request


def _handle_json_error(response_json):
Expand Down
37 changes: 21 additions & 16 deletions mcmd/commands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import mcmd.config.config as config
from mcmd import io
from mcmd.client import api
from mcmd.client.molgenis_client import post, get, post_files
from mcmd.command import command
from mcmd.commands._registry import arguments
Expand Down Expand Up @@ -131,20 +132,20 @@ def add_user(args):
superuser = args.is_superuser
ch_pwd = args.change_password

post(config.api('rest1') + 'sys_sec_User',
{'username': args.username,
'password_': password,
'changePassword': ch_pwd,
'Email': email,
'active': active,
'superuser': superuser
})
post(api.rest1('sys_sec_User'),
data={'username': args.username,
'password_': password,
'changePassword': ch_pwd,
'Email': email,
'active': active,
'superuser': superuser
})


@command
def add_group(args):
io.start('Adding group %s' % highlight(args.name))
post(config.api('group'), {'name': args.name.lower(), 'label': args.name})
post(api.group(), data={'name': args.name.lower(), 'label': args.name})


@command
Expand All @@ -157,14 +158,18 @@ def add_package(args):
if args.parent:
data['parent'] = args.parent

post(config.api('rest1') + 'sys_md_Package', data)
post(api.rest1('sys_md_Package'), data=data)


@command
def add_token(args):
io.start('Adding token %s for user %s' % (highlight(args.token), highlight(args.user)))

user = get(config.api('rest2') + 'sys_sec_User?attrs=id&q=username==%s' % args.user)
user = get(api.rest2('sys_sec_User'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want this tablename hardcoded here?

params={
'attrs': 'id',
'q': 'username=={}'.format(args.user)
})
if user.json()['total'] == 0:
raise McmdError('Unknown user %s' % args.user)

Expand All @@ -173,7 +178,7 @@ def add_token(args):
data = {'User': user_id,
'token': args.token}

post(config.api('rest1') + 'sys_sec_Token', data)
post(api.rest1('sys_sec_Token'), data=data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want this tablename hardcoded here?



@command
Expand All @@ -185,7 +190,7 @@ def add_theme(args):
"""
_validate_args(args)
valid_types = {'text/css'}
api = config.api('add_theme')
api_ = api.add_theme()
bs3_name = args.bootstrap3
bs4 = args.bootstrap4
paths = [bs3_name]
Expand All @@ -205,7 +210,7 @@ def add_theme(args):
if not args.from_path:
paths = [_get_path_from_quick_folders(theme) for theme in paths]
files = _prepare_files_for_upload(paths, names, valid_types)
post_files(files, api)
post_files(files, api_)


@command
Expand All @@ -215,7 +220,7 @@ def add_logo(args):
:param args: commandline arguments containing path to logo
:return: None
"""
api = config.api('logo')
api_ = api.logo()
valid_types = {'image/jpeg', 'image/png', 'image/gif'}
logo = [args.logo]
if not args.from_path:
Expand All @@ -224,7 +229,7 @@ def add_logo(args):
else:
io.start('Adding logo {}'.format(highlight(args.logo)))
files = _prepare_files_for_upload(logo, ['logo'], valid_types)
post_files(files, api)
post_files(files, api_)


def _prepare_files_for_upload(paths, names, valid_content_types):
Expand Down
Loading