Skip to content

Commit 3ec7334

Browse files
committed
-> Sprint 38
2 parents 43d8e37 + 7a88d87 commit 3ec7334

File tree

15 files changed

+550
-220
lines changed

15 files changed

+550
-220
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ jobs:
121121
- ./Dockerfile
122122
- ./app.yaml
123123
- ./openapi-appengine.yaml
124+
- ./gunicorn.conf.py
124125
- ./settings.py
125126
- ./txt
126127
- ./json

Dockerfile

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ ADD . /app
7171
RUN pip3 install -r /app/requirements.txt -t /app/lib/ --upgrade
7272
RUN pip3 install gunicorn==19.9.0
7373

74-
# Install Cloud SDK
75-
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && apt-get update -y && apt-get install google-cloud-sdk -y
76-
# Install the Python Libraries
77-
RUN apt-get -y install google-cloud-sdk-app-engine-python
78-
7974
ENV PYTHONPATH=/app:/app/apiv4:/app/lib:/app/ISB-CGC-Common:${PYTHONPATH}
8075

81-
CMD gunicorn -b :$PORT apiv4:app -w 3 -t 130
76+
CMD gunicorn -c gunicorn.conf.py -b :$PORT apiv4:app -w 3 -t 130

apiv4/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from flask_talisman import Talisman
2626

2727
app = Flask(__name__, static_folder='api_static')
28+
2829
Talisman(app, strict_transport_security_max_age=300, content_security_policy={
2930
'default-src': [
3031
'\'self\'',
@@ -46,6 +47,7 @@
4647
from sample_case_routes import *
4748
from file_routes import *
4849
from user_routes import *
50+
from deprecated.user_routes import *
4951

5052
logger = logging.getLogger(settings.LOGGER_NAME)
5153

@@ -56,7 +58,6 @@ def load_spec():
5658
json_spec = ""
5759
try:
5860
yaml = ruamel.yaml.YAML(typ='safe')
59-
logger.debug(os.path.split(os.path.abspath(dirname(__file__)))[0] + '/openapi-appengine.yaml')
6061
with open(os.path.split(os.path.abspath(dirname(__file__)))[0] + '/openapi-appengine.yaml') as fpi:
6162
data = yaml.load(fpi)
6263
del data['paths']['/swagger']

apiv4/cohorts_routes.py

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ def cohort(cohort_id):
4242
response_obj = None
4343

4444
if not user:
45-
response_obj = {
46-
'message': 'Encountered an error while attempting to identify this user.'
47-
}
48-
code = 500
45+
raise Exception('Encountered an error while attempting to identify this user.')
4946
else:
5047
if cohort_id <= 0:
5148
logger.warn("[WARNING] Invalid cohort ID {}".format(str(cohort_id)))
@@ -62,12 +59,8 @@ def cohort(cohort_id):
6259
cohort_info = edit_cohort(cohort_id, user, delete=(request.method == 'DELETE'))
6360

6461
if cohort_info:
65-
response_obj['data'] = cohort_info
66-
67-
if 'message' in cohort_info:
68-
code = 400
69-
else:
70-
code = 200
62+
response_obj = {'data': cohort_info}
63+
code = 400 if 'message' in cohort_info else 200
7164
else:
7265
response_obj = {
7366
'message': "Cohort ID {} was not found.".format(str(cohort_id))
@@ -111,36 +104,23 @@ def cohorts():
111104
user = validate_user(user_info['email'])
112105

113106
if not user:
114-
response_obj = {
115-
'code': 500,
116-
'message': 'Encountered an error while attempting to identify this user.'
117-
}
118-
code = 500
107+
raise Exception('Encountered an error while attempting to identify this user.')
119108
else:
120109
st_logger.write_text_log_entry(log_name, user_activity_message.format(user_info['email'], request.method, request.full_path))
121-
if request.method == 'GET':
122-
info = get_cohorts(user_info['email'])
123-
else:
124-
info = create_cohort(user)
110+
info = get_cohorts(user_info['email']) if request.method == 'GET' else create_cohort(user)
125111

126112
if info:
127-
response_obj = {}
128-
129-
if 'message' in info:
130-
code = 400
131-
else:
132-
code = 200
113+
response_obj = {
114+
'data': info
115+
}
133116

134-
response_obj['data'] = info
117+
code = 400 if 'message' in info else 200
135118

136119
# Lack of a valid object means something went wrong on the server
137120
else:
138-
response_obj = {
139-
'message': "Error while attempting to {}.".format(
140-
'retrieve the cohort list' if request.method == 'GET' else 'create this cohort'
141-
)
142-
}
143-
code = 500
121+
raise Exception("Invalid response while attempting to {}.".format(
122+
'retrieve the cohort list' if request.method == 'GET' else 'create this cohort'
123+
))
144124

145125
except UserValidationException as e:
146126
response_obj = {
@@ -161,7 +141,7 @@ def cohorts():
161141
response_obj['code'] = code
162142
response = jsonify(response_obj)
163143
response.status_code = code
164-
144+
165145
return response
166146

167147

@@ -180,10 +160,7 @@ def cohort_file_manifest(cohort_id):
180160
user = validate_user(user_info['email'], cohort_id)
181161

182162
if not user:
183-
response_obj = {
184-
'message': 'Encountered an error while attempting to identify this user.'
185-
}
186-
code = 500
163+
raise Exception('Encountered an error while attempting to identify this user.')
187164
else:
188165
if cohort_id <= 0:
189166
logger.warn("[WARNING] Invalid cohort ID {}".format(str(cohort_id)))
@@ -205,10 +182,7 @@ def cohort_file_manifest(cohort_id):
205182
'data': file_manifest
206183
}
207184
else:
208-
response_obj = {
209-
'message': "Error while attempting to retrieve file manifest for cohort {}.".format(str(cohort_id))
210-
}
211-
code = 500
185+
raise Exception("Invalid response while attempting to retrieve file manifest for cohort {}.".format(str(cohort_id)))
212186

213187
except UserValidationException as e:
214188
response_obj = {
@@ -256,11 +230,8 @@ def cohort_preview():
256230

257231
# Lack of a valid object means something went wrong on the server
258232
else:
259-
response_obj = {
260-
'message': "Error while attempting to retrieve case and sample counts for these filters."
261-
}
262-
code = 500
263-
233+
raise Exception("Invalid response while attempting to retrieve case and sample counts for these filters.")
234+
264235
except Exception as e:
265236
logger.exception(e)
266237
response_obj = {

apiv4/deprecated/__init__.py

Whitespace-only changes.

apiv4/deprecated/user_routes.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#
2+
# Copyright 2019, Institute for Systems Biology
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
import logging
18+
import json
19+
from apiv4 import app
20+
from flask import jsonify, request
21+
22+
HTTP_405_METHOD_NOT_ALLOWED = 405
23+
24+
25+
def make_405_response():
26+
response = jsonify({
27+
'code': HTTP_405_METHOD_NOT_ALLOWED,
28+
'message': "The 'gcp' path has been deprecated in version 4.1 in favor of /cloud_projects and subroutes."
29+
})
30+
31+
response.status_code = HTTP_405_METHOD_NOT_ALLOWED
32+
33+
return response
34+
35+
36+
@app.route('/v4/users/gcp/validate/<gcp_id>/', methods=['GET'], strict_slashes=False)
37+
def validate_gcp_old(gcp_id):
38+
return make_405_response()
39+
40+
41+
@app.route('/v4/users/gcp/<gcp_id>/', methods=['DELETE', 'PATCH', 'GET'], strict_slashes=False)
42+
def user_gcp_old(gcp_id):
43+
return make_405_response()
44+
45+
46+
@app.route('/v4/users/gcp/', methods=['POST', 'GET'], strict_slashes=False)
47+
def user_gcps_old():
48+
return make_405_response()

apiv4/main_routes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import logging
1818
import json
19-
from flask import jsonify, request, render_template
19+
from flask import jsonify, request, render_template, redirect, url_for
2020
from django.conf import settings
2121
from apiv4 import app
2222
from api_logging import *
@@ -31,12 +31,12 @@ def apiv4():
3131
"""Base response"""
3232

3333
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
34-
34+
3535
response = jsonify({
3636
'code': 200,
3737
'message': 'Welcome to the ISB-CGC API, Version 4.',
3838
'documentation': 'SwaggerUI interface available at <{}/swagger/>.'.format(settings.BASE_API_URL) +
39-
'Documentation available at <https://isb-cancer-genomics-cloud.readthedocs.io/en/latest/sections/progapi/Programmatic-API.html>'
39+
'Documentation available at <https://isb-cancer-genomics-cloud.readthedocs.io/en/latest/sections/progapi/progAPI-v4/Programmatic-Demo.html>'
4040
})
4141
response.status_code = 200
4242
return response

apiv4/program_routes.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,67 @@
2020
from apiv4 import app
2121
from django.conf import settings
2222
from django.db import close_old_connections
23-
from program_views import get_programs
23+
from program_views import get_cohort_programs, get_dataset_for_reg
2424
from api_logging import *
2525

2626
logger = logging.getLogger(settings.LOGGER_NAME)
2727

2828

2929
@app.route('/v4/programs/', methods=['GET'], strict_slashes=False)
3030
def programs():
31-
"""Retrieve the list of programs and builds currently available for cohort creation."""
31+
response = jsonify({
32+
'code': 405,
33+
'message': "The 'programs' path has been deprecated in version 4.1 in favor of /data/availabile and subroutes."
34+
})
35+
36+
response.status_code=405
37+
38+
return response
39+
40+
@app.route('/v4/data/available/', methods=['GET'], strict_slashes=False)
41+
def data(routes=None):
42+
"""Retrieve the list of all data available via ISB-CGC"""
3243
response = None
44+
response_obj = {}
45+
response_code = None
3346

3447
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
35-
36-
try:
3748

38-
program_info = get_programs()
39-
40-
if program_info:
41-
response = jsonify({
42-
'code': 200,
43-
'data': program_info
44-
})
45-
response.status_code = 200
46-
else:
47-
response = jsonify({
48-
'code': 500,
49-
'message': 'Encountered an error while retrieving the program list.'
50-
})
51-
response.status_code = 500
49+
try:
50+
if not routes or 'cohorts' in routes:
51+
program_info = get_cohort_programs()
52+
response_obj['programs_for_cohorts'] = program_info if program_info and len(program_info) > 0 else 'None found'
53+
54+
if not routes or 'registration' in routes:
55+
reg_info = get_dataset_for_reg()
56+
response_obj['datasets_for_registration'] = reg_info if reg_info and len(reg_info) > 0 else 'None found'
57+
58+
response_code = 200
5259
except Exception as e:
53-
logger.error("[ERROR] While retrieving program information:")
60+
logger.error("[ERROR] While retrieving data availability:")
5461
logger.exception(e)
55-
response = jsonify({
56-
'code': 500,
57-
'message': 'Encountered an error while retrieving the program list.'
58-
})
59-
response.status_code = 500
62+
response_obj = {
63+
'message': 'Encountered an error while retrieving data availability.'
64+
}
65+
response_code = 500
6066
finally:
6167
close_old_connections()
62-
68+
69+
response_obj['code'] = response_code
70+
response = jsonify(response_obj)
71+
response.status_code = response_code
72+
6373
return response
74+
75+
76+
@app.route('/v4/data/available/registration/', methods=['GET'], strict_slashes=False)
77+
def data_for_reg():
78+
"""Retrieve the list of all data available for GCP project and service account registration via ISB-CGC"""
79+
return data(['registration'])
80+
81+
82+
@app.route('/v4/data/available/cohorts/', methods=['GET'], strict_slashes=False)
83+
def data_for_cohorts():
84+
"""Retrieve the list of all data available for cohort creation via ISB-CGC"""
85+
return data(['cohorts'])
86+

apiv4/program_views.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,56 @@
2323
from django.conf import settings
2424

2525
from projects.models import Program, Project
26+
from accounts.models import AuthorizedDataset
2627

2728
logger = logging.getLogger(settings.LOGGER_NAME)
2829

2930

30-
def get_programs():
31+
def get_cohort_programs():
3132
django.setup()
3233
program_info = None
3334
try:
35+
name = request.args.get('name', default='%', type=str) if 'name' in request.args else None
36+
desc = request.args.get('desc', default='%', type=str) if 'desc' in request.args else None
37+
38+
results = Program.get_public_programs(name=name, desc=desc)
39+
3440
program_info = [
3541
{
3642
'name': x.name,
3743
'description': x.description,
38-
'projects': [{'name': y.name, 'description': y.description} for y in Project.objects.filter(program=x,active=1)]
44+
'program_privacy': "Public" if x.is_public else "User",
45+
'projects': [{'name': y.name, 'description': y.description} for y in x.get_all_projects()]
3946
}
40-
for x in Program.get_public_programs()
47+
for x in results
4148
]
4249
except Exception as e:
4350
logger.exception(e)
4451

4552
return program_info
53+
54+
55+
def get_dataset_for_reg():
56+
django.setup()
57+
datasets = None
58+
try:
59+
name = request.args.get('name', default='%', type=str) if 'name' in request.args else None
60+
id = request.args.get('id', default='%', type=str) if 'id' in request.args else None
61+
access = request.args.get('access', default='controlled', type=str) if 'access' in request.args else None
62+
63+
public = True if access.lower()=='open' else False if access.lower()=='controlled' else None
64+
65+
results = AuthorizedDataset.get_datasets(name=name, whitelist_id=id, public=public)
66+
67+
datasets = [
68+
{
69+
'name': x.name,
70+
'dataset_id': x.whitelist_id,
71+
'dataset_access': "Open" if x.public else "Controlled"
72+
}
73+
for x in results
74+
]
75+
except Exception as e:
76+
logger.exception(e)
77+
78+
return datasets

0 commit comments

Comments
 (0)