Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c32f766
update ga4gh service info endpoint, with tests and docs
teemukataja Sep 5, 2019
2026232
Merge pull request #129 from CSCfi/feature/ga4gh
blankdots Sep 16, 2019
51afbbd
Fix integer overflow in beacon_dataset_counts_table
ooobik Oct 7, 2019
c70bd0a
Merge pull request #132 from ooobik/patch-1
teemukataja Oct 8, 2019
f3534f4
fix typose deploy docs
blankdots Oct 11, 2019
2b3ae66
test exceptions db calls
blankdots Oct 11, 2019
a337e6a
checking the request here is a bit redundant
blankdots Oct 11, 2019
0bc3883
fail coverage under 80%
blankdots Oct 11, 2019
ce54db1
verify aud claim in a function
blankdots Oct 11, 2019
026a602
test token scheme just to be sure
blankdots Oct 11, 2019
c9a64a3
fix docs for validate
blankdots Oct 11, 2019
8224cad
exclude lines teste in integration tests
blankdots Oct 11, 2019
3f42e2f
fixes for db_load and its tests
blankdots Oct 11, 2019
9b94677
update jsonschema package
blankdots Oct 15, 2019
c01be2e
outdated pipfile
blankdots Oct 16, 2019
cff5bcb
bump db_load coverage
blankdots Oct 16, 2019
b5aa2b2
updates to tox
blankdots Oct 16, 2019
90c8bc1
no invalid request is ever going to reach this
blankdots Oct 16, 2019
f1c538a
fix bug in handover
blankdots Oct 16, 2019
dc614f1
test actual db responses
blankdots Oct 16, 2019
0f281d6
do not test some lines as of problematic to unit test
blankdots Oct 16, 2019
9275ecb
test db load close db connection exception
blankdots Oct 16, 2019
1b4cf69
test aud claim
blankdots Oct 16, 2019
564aace
Merge pull request #133 from CSCfi/bugfix/review-code
teemukataja Oct 17, 2019
aab89ea
first test at parsing new ga4gh passports #130
teemukataja Sep 23, 2019
ff4151b
fix controlled datasets, move validation and decoding into function #130
teemukataja Sep 24, 2019
5e663b1
check for scopes before parsing token
teemukataja Oct 14, 2019
a340551
fix documentation link
blankdots Oct 20, 2019
3245e6e
update ga4gh with fixes
blankdots Nov 1, 2019
85e885f
fix ga4gh unit tests
blankdots Nov 1, 2019
52c51af
fix permissions delivery
teemukataja Nov 5, 2019
d43543b
unit tests for ga4gh permissions
teemukataja Nov 5, 2019
e8de1cd
small fixes in unit tests
blankdots Nov 5, 2019
c7fa2bc
update mockauth for integration tests, fix bug in integtest17 and typ…
teemukataja Nov 6, 2019
bd5ab2d
update permissions docs with ga4gh implementation
blankdots Nov 6, 2019
7853803
bump version to 1.5.0
blankdots Nov 6, 2019
fa04762
Merge pull request #134 from CSCfi/feature/ga4gh-jwt-fixes
blankdots Nov 6, 2019
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
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ omit =
[report]
# Regexes for lines to exclude from consideration
exclude_lines =
pragma: no cover
# Don't complain about missing debug-only code:
def __repr__
if self\.debug
Expand Down
18 changes: 0 additions & 18 deletions Pipfile

This file was deleted.

7 changes: 5 additions & 2 deletions beacon_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
__license__ = CONFIG_INFO.license
__copyright__ = CONFIG_INFO.copyright
__docs_url__ = CONFIG_INFO.docs_url
__handover_drs__ = CONFIG_INFO.handover_drs
__handover_drs__ = CONFIG_INFO.handover_drs.rstrip("/")
__handover_datasets__ = CONFIG_INFO.handover_datasets
__handover_beacon__ = CONFIG_INFO.handover_beacon
__handover_base__ = CONFIG_INFO.handover_base
Expand All @@ -26,7 +26,6 @@
__createtime__ = CONFIG_INFO.createtime
__updatetime__ = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ') # Every restart of the application means an update to it


__org_id__ = CONFIG_INFO.org_id
__org_name__ = CONFIG_INFO.org_name
__org_description__ = CONFIG_INFO.org_description
Expand All @@ -37,3 +36,7 @@
__org_info__ = {'orgInfo': CONFIG_INFO.org_info}

__sample_queries__ = SAMPLE_QUERIES

# GA4GH Discovery
__service_type__ = f'{CONFIG_INFO.service_type}:{__apiVersion__}'
__service_env__ = CONFIG_INFO.environment
83 changes: 39 additions & 44 deletions beacon_api/api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,35 @@
from ..conf import CONFIG_INFO


class BeaconError(Exception):
"""BeaconError Exception specific class.
def process_exception_data(request, host, error_code, error):
"""Return request data as dictionary.

Generates custom exception messages based on request parameters.
"""

def __init__(self, request, host, error_code, error):
"""Return request data as dictionary."""
self.data = {'beaconId': '.'.join(reversed(host.split('.'))),
"apiVersion": __apiVersion__,
'exists': None,
'error': {'errorCode': error_code,
'errorMessage': error},
'alleleRequest': {'referenceName': request.get("referenceName", None),
'referenceBases': request.get("referenceBases", None),
'includeDatasetResponses': request.get("includeDatasetResponses", "NONE"),
'assemblyId': request.get("assemblyId", None)},
# showing empty datasetsAlleRsponse as no datasets found
# A null/None would represent no data while empty array represents
# none found or error and corresponds with exists null/None
'datasetAlleleResponses': []}
# include datasetIds only if they are specified
# as per specification if they don't exist all datatsets will be queried
# Only one of `alternateBases` or `variantType` is required, validated by schema
oneof_fields = ["alternateBases", "variantType", "start", "end", "startMin", "startMax",
"endMin", "endMax", "datasetIds"]
self.data['alleleRequest'].update({k: request.get(k) for k in oneof_fields if k in request})
return self.data


class BeaconBadRequest(BeaconError):
data = {'beaconId': '.'.join(reversed(host.split('.'))),
"apiVersion": __apiVersion__,
'exists': None,
'error': {'errorCode': error_code,
'errorMessage': error},
'alleleRequest': {'referenceName': request.get("referenceName", None),
'referenceBases': request.get("referenceBases", None),
'includeDatasetResponses': request.get("includeDatasetResponses", "NONE"),
'assemblyId': request.get("assemblyId", None)},
# showing empty datasetsAlleRsponse as no datasets found
# A null/None would represent no data while empty array represents
# none found or error and corresponds with exists null/None
'datasetAlleleResponses': []}
# include datasetIds only if they are specified
# as per specification if they don't exist all datatsets will be queried
# Only one of `alternateBases` or `variantType` is required, validated by schema
oneof_fields = ["alternateBases", "variantType", "start", "end", "startMin", "startMax",
"endMin", "endMax", "datasetIds"]
data['alleleRequest'].update({k: request.get(k) for k in oneof_fields if k in request})

return data


class BeaconBadRequest(web.HTTPBadRequest):
"""Exception returns with 400 code and a custom error message.

The method is called if one of the required parameters are missing or invalid.
Expand All @@ -49,13 +47,12 @@ class BeaconBadRequest(BeaconError):

def __init__(self, request, host, error):
"""Return custom bad request exception."""
data = super().__init__(request, host, 400, error)

LOG.error(f'400 ERROR MESSAGE: {error}')
raise web.HTTPBadRequest(content_type="application/json", text=json.dumps(data))
data = process_exception_data(request, host, 400, error)
super().__init__(text=json.dumps(data), content_type="application/json")
LOG.error(f'401 ERROR MESSAGE: {error}')


class BeaconUnauthorised(BeaconError):
class BeaconUnauthorised(web.HTTPUnauthorized):
"""HTTP Exception returns with 401 code with a custom error message.

The method is called if the user is not registered or if the token from the authentication has expired.
Expand All @@ -64,17 +61,17 @@ class BeaconUnauthorised(BeaconError):

def __init__(self, request, host, error, error_message):
"""Return custom unauthorized exception."""
data = super().__init__(request, host, 401, error)
data = process_exception_data(request, host, 401, error)
headers_401 = {"WWW-Authenticate": f"Bearer realm=\"{CONFIG_INFO.url}\"\n\
error=\"{error}\"\n\
error_description=\"{error_message}\""}
super().__init__(content_type="application/json", text=json.dumps(data),
# we use auth scheme Bearer by default
headers=headers_401)
LOG.error(f'401 ERROR MESSAGE: {error}')
raise web.HTTPUnauthorized(content_type="application/json", text=json.dumps(data),
# we use auth scheme Bearer by default
headers=headers_401)


class BeaconForbidden(BeaconError):
class BeaconForbidden(web.HTTPForbidden):
"""HTTP Exception returns with 403 code with the error message.

`'Resource not granted for authenticated user or resource protected for all users.'`.
Expand All @@ -84,13 +81,12 @@ class BeaconForbidden(BeaconError):

def __init__(self, request, host, error):
"""Return custom forbidden exception."""
data = super().__init__(request, host, 403, error)

data = process_exception_data(request, host, 403, error)
super().__init__(content_type="application/json", text=json.dumps(data))
LOG.error(f'403 ERROR MESSAGE: {error}')
raise web.HTTPForbidden(content_type="application/json", text=json.dumps(data))


class BeaconServerError(BeaconError):
class BeaconServerError(web.HTTPInternalServerError):
"""HTTP Exception returns with 500 code with the error message.

The 500 error is not specified by the Beacon API, thus as simple error would do.
Expand All @@ -100,6 +96,5 @@ def __init__(self, error):
"""Return custom forbidden exception."""
data = {'errorCode': 500,
'errorMessage': error}

super().__init__(content_type="application/json", text=json.dumps(data))
LOG.error(f'500 ERROR MESSAGE: {error}')
raise web.HTTPInternalServerError(content_type="application/json", text=json.dumps(data))
17 changes: 11 additions & 6 deletions beacon_api/api/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .. import __apiVersion__, __title__, __version__, __description__, __url__, __alturl__, __handover_beacon__
from .. import __createtime__, __updatetime__, __org_id__, __org_name__, __org_description__
from .. import __org_address__, __org_logoUrl__, __org_welcomeUrl__, __org_info__, __org_contactUrl__
from .. import __sample_queries__, __handover_drs__, __docs_url__
from .. import __sample_queries__, __handover_drs__, __docs_url__, __service_type__, __service_env__
from ..utils.data_query import fetch_dataset_metadata
from ..extensions.handover import make_handover
from aiocache import cached
Expand All @@ -26,13 +26,18 @@ async def ga4gh_info(host):
# TO DO implement some fallback mechanism for ID
'id': '.'.join(reversed(host.split('.'))),
'name': __title__,
"type": "urn:ga4gh:beacon",
"type": __service_type__,
'description': __description__,
'documentationUrl': __docs_url__,
"organization": __org_id__,
"organization": {
"name": __org_name__,
"url": __org_welcomeUrl__,
},
'contactUrl': __org_contactUrl__,
'version': __version__,
"extension": {}
'documentationUrl': __docs_url__,
'createdAt': __createtime__,
'updatedAt': __updatetime__,
'environment': __service_env__,
'version': __version__
}
return beacon_info

Expand Down
3 changes: 2 additions & 1 deletion beacon_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ async def initialize(app):

async def destroy(app):
"""Upon server close, close the DB connection pool."""
await app['pool'].close()
# will defer this to asyncpg
await app['pool'].close() # pragma: no cover


def set_cors(server):
Expand Down
2 changes: 2 additions & 0 deletions beacon_api/conf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def parse_config_file(path):
'url': config.get('beacon_api_info', 'url'),
'alturl': config.get('beacon_api_info', 'alturl'),
'createtime': config.get('beacon_api_info', 'createtime'),
'service_type': config.get('beacon_api_info', 'service_type'),
'environment': config.get('beacon_api_info', 'environment'),
'org_id': config.get('organisation_info', 'org_id'),
'org_name': config.get('organisation_info', 'org_name'),
'org_description': config.get('organisation_info', 'org_description'),
Expand Down
9 changes: 8 additions & 1 deletion beacon_api/conf/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
title=GA4GHBeacon at CSC

# Version of the Beacon implementation
version=1.4.0
version=1.5.0

# Author of this software
author=CSC developers
Expand Down Expand Up @@ -41,6 +41,13 @@ alturl=
# Datetime when this Beacon was created
createtime=2018-07-25T00:00:00Z

# GA4GH Discovery type `groupId` and `artifactId`, joined in /service-info with apiVersion
# See https://github.com/ga4gh-discovery/ga4gh-service-registry for more information and possible values
service_type=org.ga4gh:beacon

# GA4GH Discovery server environment, possible values: prod, dev, test
environment=prod


[organisation_info]
# Globally unique identifier for organisation that hosts this Beacon service
Expand Down
4 changes: 2 additions & 2 deletions beacon_api/extensions/handover.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def make_handover(paths, datasetIds, chr='', start=0, end=0, ref='', alt='', var
for dataset in set(datasetIds):
handovers.append({"handoverType": {"id": "CUSTOM", "label": label},
"description": desc,
"url": __handover_drs__ + path.format(dataset=dataset, chr=chr, start=start,
end=end, ref=ref, alt=alt)})
"url": __handover_drs__ + "/" + path.format(dataset=dataset, chr=chr, start=start,
end=end, ref=ref, alt=alt)})

return handovers
Loading