Skip to content

Commit 43d8e37

Browse files
authored
Merge pull request #370 from isb-cgc/prod-sp
Sprint 37
2 parents 6ee1660 + 4984805 commit 43d8e37

14 files changed

+153
-97
lines changed

.circleci/config.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ jobs:
113113
command: |
114114
sudo -E /bin/bash ./shell/gcloud-pull-staging-files.sh
115115
- save_cache:
116-
key: isb-cgc-api-{{ epoch }}
116+
key: isb-cgc-api-{{ .Branch }}-{{ .Revision }}-{{ epoch }}
117117
paths:
118118
- ./apiv4
119119
- ./shell
@@ -125,7 +125,6 @@ jobs:
125125
- ./txt
126126
- ./json
127127
- ./.env
128-
129128
deploy_job:
130129
environment:
131130
TZ: "/usr/share/zoneinfo/America/Los_Angeles"
@@ -135,7 +134,7 @@ jobs:
135134
steps:
136135
- restore_cache:
137136
keys:
138-
- isb-cgc-api-
137+
- isb-cgc-api-{{ .Branch }}-{{ .Revision }}-
139138
- restore_cache:
140139
keys:
141140
- isb-cgc-api-google-deps-

apiv4/api_logging.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django.conf import settings
2+
from google_helpers.stackdriver import StackDriverLogger
3+
4+
# Log all API activity to StackDriver
5+
st_logger = StackDriverLogger.build_from_django_settings()
6+
log_name = settings.API_ACTIVITY_LOG_NAME
7+
user_activity_message = "[USER API CALL] User {} performing method {} path {}"
8+
activity_message = "[API CALL] Saw method {} for path {}"

apiv4/auth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def auth_info():
5454
if 'email' not in user_info:
5555
raise UserValidationException("Couldn't obtain user email - the correct scopes may not have been provided during authorization!")
5656
else:
57-
logger.info("[STATUS] No user encoded info found.")
57+
logger.warn("[WARNING] No user encoded info found.")
5858
user_info = {'id': 'anonymous', 'email': 'Anonymous'}
5959

6060
return user_info
@@ -71,6 +71,7 @@ def get_user(user_email=None):
7171
django.setup()
7272
try:
7373
user = Django_User.objects.get(email=user_email)
74+
logger.info("[USER API AUTH] User {} seen in API".format(user_email))
7475
except ObjectDoesNotExist as e:
7576
logger.warn("User {} does not exist in our system.".format(user_email))
7677
raise UserValidationException(

apiv4/cohorts_routes.py

Lines changed: 80 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from auth import auth_info, UserValidationException, validate_user
2323
from django.conf import settings
2424
from django.db import close_old_connections
25+
from api_logging import *
2526

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

@@ -37,57 +38,60 @@ def cohort(cohort_id):
3738
user_info = auth_info()
3839
user = validate_user(user_info['email'], cohort_id)
3940

40-
response = None
4141
code = None
42+
response_obj = None
4243

4344
if not user:
44-
response = jsonify({
45-
'code': 500,
45+
response_obj = {
4646
'message': 'Encountered an error while attempting to identify this user.'
47-
})
48-
response.status_code = 500
47+
}
48+
code = 500
4949
else:
50-
if request.method == 'GET':
51-
include_barcodes = (request.args.get('include_barcodes', default="false", type=str).lower() == "true")
52-
cohort_info = get_cohort_info(cohort_id, include_barcodes)
50+
if cohort_id <= 0:
51+
logger.warn("[WARNING] Invalid cohort ID {}".format(str(cohort_id)))
52+
code = 400
53+
response_obj = {
54+
'message': '"{}" is not a valid cohort ID.'.format(str(cohort_id))
55+
}
5356
else:
54-
cohort_info = edit_cohort(cohort_id, user, delete=(request.method == 'DELETE'))
57+
st_logger.write_text_log_entry(log_name, user_activity_message.format(user_info['email'], request.method, request.full_path))
58+
if request.method == 'GET':
59+
include_barcodes = (request.args.get('include_barcodes', default="false", type=str).lower() == "true")
60+
cohort_info = get_cohort_info(cohort_id, include_barcodes)
61+
else:
62+
cohort_info = edit_cohort(cohort_id, user, delete=(request.method == 'DELETE'))
5563

56-
if cohort_info:
57-
response_obj = {}
64+
if cohort_info:
65+
response_obj['data'] = cohort_info
5866

59-
if 'message' in cohort_info:
60-
code = 400
67+
if 'message' in cohort_info:
68+
code = 400
69+
else:
70+
code = 200
6171
else:
62-
code = 200
63-
64-
response_obj['data'] = cohort_info
65-
response_obj['code'] = code
66-
response = jsonify(response_obj)
67-
response.status_code = code
68-
69-
else:
70-
response = jsonify({
71-
'code': 404,
72-
'message': "Cohort ID {} was not found.".format(str(cohort_id))})
73-
response.status_code = 404
72+
response_obj = {
73+
'message': "Cohort ID {} was not found.".format(str(cohort_id))
74+
}
75+
code = 404
7476

7577
except UserValidationException as e:
76-
response = jsonify({
77-
'code': 403,
78+
response_obj = {
7879
'message': str(e)
79-
})
80-
response.status_code = 403
80+
}
81+
code = 403
8182
except Exception as e:
8283
logger.exception(e)
83-
response = jsonify({
84-
'code': 500,
84+
response_obj = {
8585
'message': 'Encountered an error while attempting to retrieve this cohort\'s information.'
86-
})
87-
response.status_code = 500
86+
}
87+
code = 500
8888
finally:
8989
close_old_connections()
9090

91+
response_obj['code'] = code
92+
response = jsonify(response_obj)
93+
response.status_code = code
94+
9195
return response
9296

9397

@@ -98,7 +102,7 @@ def cohorts():
98102
POST: Add a new cohort
99103
"""
100104

101-
response = None
105+
response_obj = None
102106
info = None
103107
code = None
104108

@@ -107,58 +111,57 @@ def cohorts():
107111
user = validate_user(user_info['email'])
108112

109113
if not user:
110-
response = jsonify({
114+
response_obj = {
111115
'code': 500,
112116
'message': 'Encountered an error while attempting to identify this user.'
113-
})
114-
response.status_code = 500
117+
}
118+
code = 500
115119
else:
120+
st_logger.write_text_log_entry(log_name, user_activity_message.format(user_info['email'], request.method, request.full_path))
116121
if request.method == 'GET':
117122
info = get_cohorts(user_info['email'])
118123
else:
119124
info = create_cohort(user)
120125

121126
if info:
122127
response_obj = {}
123-
128+
124129
if 'message' in info:
125130
code = 400
126131
else:
127132
code = 200
128133

129134
response_obj['data'] = info
130-
response_obj['code'] = code
131-
response = jsonify(response_obj)
132-
response.status_code = code
133135

134136
# Lack of a valid object means something went wrong on the server
135137
else:
136-
response = jsonify({
137-
'code': 500,
138+
response_obj = {
138139
'message': "Error while attempting to {}.".format(
139140
'retrieve the cohort list' if request.method == 'GET' else 'create this cohort'
140141
)
141-
})
142-
response.status_code = 500
142+
}
143+
code = 500
143144

144145
except UserValidationException as e:
145-
response = jsonify({
146-
'code': 403,
146+
response_obj = {
147147
'message': str(e)
148-
})
149-
response.status_code = 403
148+
}
149+
code = 403
150150
except Exception as e:
151151
logger.exception(e)
152-
response = jsonify({
153-
'code': 500,
152+
response_obj = {
154153
'message': 'Encountered an error while attempting to {}.'.format(
155154
"retrieve a list of cohorts" if request.method == 'GET' else "create this cohort"
156155
)
157-
})
158-
response.status_code = 500
156+
}
157+
code = 500
159158
finally:
160159
close_old_connections()
161-
160+
161+
response_obj['code'] = code
162+
response = jsonify(response_obj)
163+
response.status_code = code
164+
162165
return response
163166

164167

@@ -182,22 +185,30 @@ def cohort_file_manifest(cohort_id):
182185
}
183186
code = 500
184187
else:
185-
file_manifest = get_file_manifest(cohort_id, user)
186-
if file_manifest:
187-
# Presence of a message means something went wrong with our request
188-
if 'message' in file_manifest:
189-
response_obj = file_manifest
190-
code = 400
188+
if cohort_id <= 0:
189+
logger.warn("[WARNING] Invalid cohort ID {}".format(str(cohort_id)))
190+
code = 400
191+
response_obj = {
192+
'message': '"{}" is not a valid cohort ID.'.format(str(cohort_id))
193+
}
194+
else:
195+
st_logger.write_text_log_entry(log_name, user_activity_message.format(user_info['email'], request.method, request.full_path))
196+
file_manifest = get_file_manifest(cohort_id, user)
197+
if file_manifest:
198+
# Presence of a message means something went wrong with our request
199+
if 'message' in file_manifest:
200+
response_obj = file_manifest
201+
code = 400
202+
else:
203+
code = 200
204+
response_obj = {
205+
'data': file_manifest
206+
}
191207
else:
192-
code = 200
193208
response_obj = {
194-
'data': file_manifest
209+
'message': "Error while attempting to retrieve file manifest for cohort {}.".format(str(cohort_id))
195210
}
196-
else:
197-
response_obj = {
198-
'message': "Error while attempting to retrieve file manifest for cohort {}.".format(str(cohort_id))
199-
}
200-
code = 500
211+
code = 500
201212

202213
except UserValidationException as e:
203214
response_obj = {
@@ -227,6 +238,8 @@ def cohort_preview():
227238
code = None
228239
response_obj = None
229240

241+
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
242+
230243
try:
231244
cohort_counts = get_cohort_counts()
232245

apiv4/cohorts_views.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,17 @@ def get_file_manifest(cohort_id, user):
5959
'offset': {'default': 0, 'type': int, 'name': 'offset'},
6060
'page': {'default': 1, 'type': int, 'name': 'page'},
6161
'fetch_count': {'default': 5000, 'type': int, 'name': 'limit'},
62-
'genomic_build': {'default': "HG19", 'type': str, 'name': 'build'}
62+
'genomic_build': {'default': "HG19", 'type': str, 'name': 'build'},
63+
'case_insensitive': {'default': "True", 'type': str, 'name': 'case_insensitive'}
6364
}
6465

6566
for param, parameter in param_set.items():
6667
default = parameter['default']
6768
param_type = parameter['type']
6869
name = parameter['name']
6970
params[name] = request_data[param] if (request_data and param in request_data) else request.args.get(param, default=default, type=param_type) if param in request.args else default
71+
if name == 'case_insensitive':
72+
params[name] = bool(params[name] == "True")
7073

7174
if request_data:
7275
inc_filters = {
@@ -150,7 +153,9 @@ def get_cohort_counts():
150153
'message': 'No filters were provided; ensure that the request body contains a \'filters\' property.'
151154
}
152155
else:
153-
cohort_counts = get_sample_case_list_bq(None, request_data['filters'])
156+
case_insensitive = request_data['case_insensitive'] if (request_data and 'case_insensitive' in request_data) else request.args.get('case_insensitive', default="True", type=str) if 'case_insensitive' in request.args else "True"
157+
158+
cohort_counts = get_sample_case_list_bq(None, request_data['filters'], case_insens=bool(case_insensitive == "True"))
154159

155160
if cohort_counts:
156161
for prog in cohort_counts:
@@ -207,6 +212,10 @@ def create_cohort(user):
207212
}
208213

209214
else:
215+
case_insensitive = request_data['case_insensitive'] if (request_data and 'case_insensitive' in request_data) else request.args.get('case_insensitive', default="True", type=str) if 'case_insensitive' in request.args else "True"
216+
request_data.pop('case_insensitive', None)
217+
request_data['case_insens'] = bool(case_insensitive == 'True')
218+
210219
result = make_cohort(user, **request_data)
211220

212221
if 'message' in result:

apiv4/file_routes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from django.db import close_old_connections
2323
from auth import validate_user, UserValidationException
2424
from file_views import get_file_paths, get_signed_uris
25+
from api_logging import *
2526

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

@@ -122,6 +123,8 @@ def file_path(file_uuid):
122123
resp_obj = None
123124
code = None
124125

126+
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
127+
125128
try:
126129
file_paths = get_file_paths(file_uuid)
127130

@@ -163,6 +166,8 @@ def file_path_list():
163166

164167
response_obj = None
165168

169+
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
170+
166171
try:
167172
file_paths = get_file_paths()
168173

@@ -199,4 +204,3 @@ def file_path_list():
199204
response.status_code = code
200205

201206
return response
202-

apiv4/main_routes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from flask import jsonify, request, render_template
2020
from django.conf import settings
2121
from apiv4 import app
22+
from api_logging import *
2223

2324
logger = logging.getLogger(settings.LOGGER_NAME)
2425

@@ -28,6 +29,9 @@
2829
@app.route('/v4/about/', methods=['GET'], strict_slashes=False)
2930
def apiv4():
3031
"""Base response"""
32+
33+
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
34+
3135
response = jsonify({
3236
'code': 200,
3337
'message': 'Welcome to the ISB-CGC API, Version 4.',
@@ -41,6 +45,7 @@ def apiv4():
4145
# Swagger UI
4246
@app.route('/v4/swagger/', methods=['GET'], strict_slashes=False)
4347
def swagger():
48+
st_logger.write_text_log_entry(log_name, activity_message.format(request.method, request.full_path))
4449
return render_template('swagger/index.html')
4550

4651

0 commit comments

Comments
 (0)