Skip to content

Commit cdadbfe

Browse files
committed
Add download model functionality
1 parent 86c4f95 commit cdadbfe

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

cesium_app/app_server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ def make_app(cfg, baselayer_handlers, baselayer_settings):
5757
(r'/project(/.*)?', ProjectHandler),
5858
(r'/dataset(/.*)?', DatasetHandler),
5959
(r'/features(/.*)?', FeatureHandler),
60-
(r'/models(/.*)?', ModelHandler),
60+
(r'/models(/[0-9]+)?', ModelHandler),
61+
(r'/models/([0-9]+)/(download)', ModelHandler),
6162
(r'/predictions(/[0-9]+)?', PredictionHandler),
6263
(r'/predictions/([0-9]+)/(download)', PredictionHandler),
6364
(r'/predict_raw_data', PredictRawDataHandler),

cesium_app/handlers/model.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,24 @@ def _build_model_compute_statistics(fset_path, model_type, model_params,
7272

7373
class ModelHandler(BaseHandler):
7474
@auth_or_token
75-
def get(self, model_id=None):
76-
if model_id is not None:
77-
model_info = Model.get_if_owned_by(model_id, self.current_user)
75+
def get(self, model_id=None, action=None):
76+
if action == 'download':
77+
model_path = Model.get_if_owned_by(model_id,
78+
self.current_user).file_uri
79+
with open(model_path, 'rb') as f:
80+
model_data = f.read()
81+
self.set_header("Content-Type", "application/octet-stream")
82+
self.set_header("Content-Disposition", "attachment; "
83+
"filename=cesium_model__joblib.pkl")
84+
self.write(model_data)
7885
else:
79-
model_info = [model for p in self.current_user.projects
80-
for model in p.models]
86+
if model_id is not None:
87+
model_info = Model.get_if_owned_by(model_id, self.current_user)
88+
else:
89+
model_info = [model for p in self.current_user.projects
90+
for model in p.models]
8191

82-
return self.success(model_info)
92+
return self.success(model_info)
8393

8494
@auth_or_token
8595
async def _await_model_statistics(self, model_stats_future, model):

static/css/base.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ body {
3333
.loginBox .logo {
3434
float: left;
3535
padding: 1em;
36-
}
36+
}
37+
a:hover {
38+
cursor:pointer;
39+
}

static/js/components/Download.jsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
3+
const Download = (props) => {
4+
const style = {
5+
display: 'inline-block'
6+
};
7+
return (
8+
<a
9+
href={props.url}
10+
style={style}
11+
onClick={
12+
(e) => {
13+
e.stopPropagation();
14+
}
15+
}
16+
>
17+
Download
18+
</a>
19+
);
20+
};
21+
Download.propTypes = {
22+
ID: React.PropTypes.oneOfType([
23+
React.PropTypes.number,
24+
React.PropTypes.string]).isRequired,
25+
url: React.PropTypes.string.isRequired
26+
};
27+
28+
export default Download;

static/js/components/Models.jsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as Validate from '../validate';
1010
import * as Action from '../actions';
1111
import Expand from './Expand';
1212
import Delete from './Delete';
13+
import Download from './Download';
1314
import { $try, reformatDatetime } from '../utils';
1415
import FoldableRow from './FoldableRow';
1516

@@ -237,7 +238,11 @@ export let ModelTable = props => (
237238
<td>{model.name}</td>
238239
<td>{reformatDatetime(model.created_at)}</td>
239240
{status}
240-
<td><DeleteModel ID={model.id} /></td>
241+
<td>
242+
<Download url={`/models/${model.id}/download`} />
243+
&nbsp;&nbsp;
244+
<DeleteModelButton ID={model.id} />
245+
</td>
241246
</tr>
242247
{foldedContent}
243248
</FoldableRow>
@@ -265,11 +270,10 @@ const mtMapStateToProps = (state, ownProps) => (
265270
ModelTable = connect(mtMapStateToProps)(ModelTable);
266271

267272

268-
const dmMapDispatchToProps = dispatch => (
273+
const deleteMapDispatchToProps = dispatch => (
269274
{ delete: id => dispatch(Action.deleteModel(id)) }
270275
);
271-
272-
const DeleteModel = connect(null, dmMapDispatchToProps)(Delete);
276+
const DeleteModelButton = connect(null, deleteMapDispatchToProps)(Delete);
273277

274278

275279
export default ModelsTab;

0 commit comments

Comments
 (0)