Skip to content

Commit ef20722

Browse files
authored
Merge pull request #227 from acrellin/master
Use new auth_or_token decorators in handlers
2 parents 72830c4 + 8737958 commit ef20722

File tree

9 files changed

+81
-53
lines changed

9 files changed

+81
-53
lines changed

cesium_app/handlers/dataset.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from baselayer.app.handlers.base import BaseHandler
22
from baselayer.app.custom_exceptions import AccessError
3+
from baselayer.app.access import auth_or_token
34
from ..models import DBSession, Project, Dataset, DatasetFile
45
from .. import util
56

@@ -9,39 +10,52 @@
910
import os
1011
from os.path import join as pjoin
1112
import uuid
12-
13-
import tornado.web
13+
import base64
14+
import tarfile
1415

1516

1617
class DatasetHandler(BaseHandler):
17-
@tornado.web.authenticated
18+
@auth_or_token
1819
def post(self):
19-
if not 'tarFile' in self.request.files:
20+
data = self.get_json()
21+
if not 'tarFile' in data:
2022
return self.error('No tar file uploaded')
2123

22-
zipfile = self.request.files['tarFile'][0]
24+
zipfile = data['tarFile']
25+
tarball_content_type_str = 'data:application/gzip;base64,'
26+
27+
if not zipfile['body'].startswith(tarball_content_type_str):
28+
return self.error('Invalid tar file - please ensure file is gzip '
29+
'format.')
2330

24-
if zipfile.filename == '':
31+
if zipfile['name'] == '':
2532
return self.error('Empty tar file uploaded')
2633

27-
dataset_name = self.get_argument('datasetName')
28-
project_id = self.get_argument('projectID')
34+
dataset_name = data['datasetName']
35+
project_id = data['projectID']
2936

3037
zipfile_name = (str(uuid.uuid4()) + "_" +
31-
util.secure_filename(zipfile.filename))
38+
util.secure_filename(zipfile['name']))
3239
zipfile_path = pjoin(self.cfg['paths:upload_folder'], zipfile_name)
3340

3441
with open(zipfile_path, 'wb') as f:
35-
f.write(zipfile['body'])
42+
f.write(base64.b64decode(
43+
zipfile['body'].replace(tarball_content_type_str, '')))
44+
try:
45+
tarfile.open(zipfile_path)
46+
except tarfile.ReadError:
47+
os.remove(zipfile_path)
48+
return self.error('Invalid tar file - please ensure file is gzip '
49+
'format.')
3650

3751
# Header file is optional for unlabled data w/o metafeatures
38-
if 'headerFile' in self.request.files:
39-
headerfile = self.request.files['headerFile'][0]
52+
if 'headerFile' in data:
53+
headerfile = data['headerFile']
4054
headerfile_name = (str(uuid.uuid4()) + "_" +
41-
util.secure_filename(headerfile.filename))
55+
util.secure_filename(headerfile['name']))
4256
headerfile_path = pjoin(self.cfg['paths:upload_folder'], headerfile_name)
4357

44-
with open(headerfile_path, 'wb') as f:
58+
with open(headerfile_path, 'w') as f:
4559
f.write(headerfile['body'])
4660

4761
else:
@@ -67,7 +81,7 @@ def post(self):
6781

6882
return self.success(d, 'cesium/FETCH_DATASETS')
6983

70-
@tornado.web.authenticated
84+
@auth_or_token
7185
def get(self, dataset_id=None):
7286
if dataset_id is not None:
7387
dataset = Dataset.get_if_owned_by(dataset_id, self.current_user)
@@ -79,7 +93,7 @@ def get(self, dataset_id=None):
7993

8094
return self.success(dataset_info)
8195

82-
@tornado.web.authenticated
96+
@auth_or_token
8397
def delete(self, dataset_id):
8498
d = Dataset.get_if_owned_by(dataset_id, self.current_user)
8599
DBSession().delete(d)

cesium_app/handlers/feature.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import tornado.ioloop
2-
import tornado.web
32

43
from cesium import featurize, time_series
54
from cesium.features import dask_feature_graph
65

76
from baselayer.app.handlers.base import BaseHandler
87
from baselayer.app.custom_exceptions import AccessError
8+
from baselayer.app.access import auth_or_token
99
from ..models import DBSession, Dataset, Featureset, Project
1010

1111
from os.path import join as pjoin
@@ -14,7 +14,7 @@
1414

1515

1616
class FeatureHandler(BaseHandler):
17-
@tornado.web.authenticated
17+
@auth_or_token
1818
def get(self, featureset_id=None):
1919
if featureset_id is not None:
2020
featureset_info = Featureset.get_if_owned_by(featureset_id,
@@ -25,7 +25,7 @@ def get(self, featureset_id=None):
2525

2626
self.success(featureset_info)
2727

28-
@tornado.web.authenticated
28+
@auth_or_token
2929
async def _await_featurization(self, future, fset):
3030
"""Note: we cannot use self.error / self.success here. There is
3131
no longer an active, open request by the time this happens!
@@ -53,7 +53,7 @@ async def _await_featurization(self, future, fset):
5353

5454
self.action('cesium/FETCH_FEATURESETS')
5555

56-
@tornado.web.authenticated
56+
@auth_or_token
5757
async def post(self):
5858
data = self.get_json()
5959
featureset_name = data.get('featuresetName', '')
@@ -104,14 +104,14 @@ async def post(self):
104104

105105
self.success(fset, 'cesium/FETCH_FEATURESETS')
106106

107-
@tornado.web.authenticated
107+
@auth_or_token
108108
def delete(self, featureset_id):
109109
f = Featureset.get_if_owned_by(featureset_id, self.current_user)
110110
DBSession().delete(f)
111111
DBSession().commit()
112112
self.success(action='cesium/FETCH_FEATURESETS')
113113

114-
@tornado.web.authenticated
114+
@auth_or_token
115115
def put(self, featureset_id):
116116
f = Featureset.get_if_owned_by(featureset_id, self.current_user)
117117
self.error("Functionality for this endpoint is not yet implemented.")

cesium_app/handlers/model.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from baselayer.app.handlers.base import BaseHandler
22
from baselayer.app.custom_exceptions import AccessError
3+
from baselayer.app.access import auth_or_token
34
from ..models import DBSession, Project, Model, Featureset
45
from ..ext.sklearn_models import (
56
model_descriptions as sklearn_model_descriptions,
@@ -16,7 +17,7 @@
1617
import joblib
1718

1819
import tornado.ioloop
19-
import tornado.web
20+
2021

2122
def _build_model_compute_statistics(fset_path, model_type, model_params,
2223
params_to_optimize, model_path):
@@ -70,7 +71,7 @@ def _build_model_compute_statistics(fset_path, model_type, model_params,
7071

7172

7273
class ModelHandler(BaseHandler):
73-
@tornado.web.authenticated
74+
@auth_or_token
7475
def get(self, model_id=None):
7576
if model_id is not None:
7677
model_info = Model.get_if_owned_by(model_id, self.current_user)
@@ -80,7 +81,7 @@ def get(self, model_id=None):
8081

8182
return self.success(model_info)
8283

83-
@tornado.web.authenticated
84+
@auth_or_token
8485
async def _await_model_statistics(self, model_stats_future, model):
8586
try:
8687
score, best_params = await model_stats_future
@@ -105,7 +106,7 @@ async def _await_model_statistics(self, model_stats_future, model):
105106

106107
self.action('cesium/FETCH_MODELS')
107108

108-
@tornado.web.authenticated
109+
@auth_or_token
109110
async def post(self):
110111
data = self.get_json()
111112

@@ -152,7 +153,7 @@ async def post(self):
152153
return self.success(data={'message': "Model training begun."},
153154
action='cesium/FETCH_MODELS')
154155

155-
@tornado.web.authenticated
156+
@auth_or_token
156157
def delete(self, model_id):
157158
m = Model.get_if_owned_by(model_id, self.current_user)
158159
DBSession().delete(m)

cesium_app/handlers/plot_features.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
from .. import plot
33
from ..models import Featureset
44

5-
import tornado.web
6-
75

86
class PlotFeaturesHandler(BaseHandler):
97
def get(self, featureset_id):

cesium_app/handlers/prediction.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from baselayer.app.handlers.base import BaseHandler
22
from baselayer.app.custom_exceptions import AccessError
3+
from baselayer.app.access import auth_or_token
34
from ..models import DBSession, Prediction, Dataset, Model, Project
45
from .. import util
56

67
import tornado.gen
7-
from tornado.web import RequestHandler
88
from tornado.escape import json_decode
99

1010
from cesium import featurize, time_series
@@ -51,7 +51,7 @@ async def _await_prediction(self, future, prediction):
5151

5252
self.action('cesium/FETCH_PREDICTIONS')
5353

54-
@tornado.web.authenticated
54+
@auth_or_token
5555
async def post(self):
5656
data = self.get_json()
5757

@@ -118,7 +118,7 @@ async def post(self):
118118

119119
return self.success(prediction.display_info(), 'cesium/FETCH_PREDICTIONS')
120120

121-
@tornado.web.authenticated
121+
@auth_or_token
122122
def get(self, prediction_id=None, action=None):
123123
if action == 'download':
124124
pred_path = Prediction.get_if_owned_by(prediction_id,
@@ -149,7 +149,7 @@ def get(self, prediction_id=None, action=None):
149149

150150
return self.success(prediction_info)
151151

152-
@tornado.web.authenticated
152+
@auth_or_token
153153
def delete(self, prediction_id):
154154
prediction = Prediction.get_if_owned_by(prediction_id,
155155
self.current_user)
@@ -159,7 +159,7 @@ def delete(self, prediction_id):
159159

160160

161161
class PredictRawDataHandler(BaseHandler):
162-
@tornado.web.authenticated
162+
@auth_or_token
163163
def post(self):
164164
ts_data = json_decode(self.get_argument('ts_data'))
165165
model_id = json_decode(self.get_argument('modelID'))

cesium_app/handlers/project.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from baselayer.app.handlers.base import BaseHandler
22
from baselayer.app.custom_exceptions import AccessError
3+
from baselayer.app.access import auth_or_token
34
from ..models import DBSession, Project
4-
import tornado.web
55

66

77
class ProjectHandler(BaseHandler):
8-
@tornado.web.authenticated
8+
@auth_or_token
99
def get(self, project_id=None):
1010
if project_id is not None:
1111
proj_info = Project.get_if_owned_by(project_id, self.current_user)
@@ -14,7 +14,7 @@ def get(self, project_id=None):
1414

1515
return self.success(proj_info)
1616

17-
@tornado.web.authenticated
17+
@auth_or_token
1818
def post(self):
1919
data = self.get_json()
2020

@@ -26,7 +26,7 @@ def post(self):
2626

2727
return self.success({"id": p.id}, 'cesium/FETCH_PROJECTS')
2828

29-
@tornado.web.authenticated
29+
@auth_or_token
3030
def put(self, project_id):
3131
# This ensures that the user has access to the project they
3232
# want to modify
@@ -39,7 +39,7 @@ def put(self, project_id):
3939

4040
return self.success(action='cesium/FETCH_PROJECTS')
4141

42-
@tornado.web.authenticated
42+
@auth_or_token
4343
def delete(self, project_id):
4444
p = Project.get_if_owned_by(project_id, self.current_user)
4545
DBSession().delete(p)

cesium_app/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import sqlalchemy as sa
55
from sqlalchemy.orm import relationship
66

7-
from baselayer.app.models import (init_db, join_model, Base, DBSession, User)
7+
from baselayer.app.models import (init_db, join_model, Base, DBSession, User,
8+
Token)
89
from cesium import featurize
910

1011

static/js/actions.js

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -186,26 +186,40 @@ export function deleteProject(id) {
186186

187187

188188
export function uploadDataset(form) {
189-
const formData = new FormData();
190189

191-
for (const key in form) {
192-
if (form[key] && objectType(form[key][0]) === 'File') {
193-
formData.append(key, form[key][0]);
194-
} else {
195-
formData.append(key, form[key]);
196-
}
190+
function fileReaderPromise(form, fileName, binary = false){
191+
return new Promise(resolve => {
192+
var filereader = new FileReader();
193+
if (binary) {
194+
filereader.readAsDataURL(form[fileName][0]);
195+
} else {
196+
filereader.readAsText(form[fileName][0]);
197+
}
198+
filereader.onloadend = () => resolve({ body: filereader.result,
199+
name: form[fileName][0].name });
200+
});
197201
}
198202

199203
return dispatch =>
200204
promiseAction(
201205
dispatch,
202206
UPLOAD_DATASET,
203207

204-
fetch('/dataset', {
205-
credentials: 'same-origin',
206-
method: 'POST',
207-
body: formData
208-
})
208+
Promise.all([fileReaderPromise(form, 'headerFile'),
209+
fileReaderPromise(form, 'tarFile', true)])
210+
.then(([headerData, tarData]) => {
211+
form['headerFile'] = headerData;
212+
form['tarFile'] = tarData;
213+
214+
return fetch('/dataset', {
215+
credentials: 'same-origin',
216+
method: 'POST',
217+
body: JSON.stringify(form),
218+
headers: new Headers({
219+
'Content-Type': 'application/json'
220+
})
221+
})
222+
})
209223
.then(response => response.json())
210224
.then((json) => {
211225
if (json.status == 'success') {

0 commit comments

Comments
 (0)