1
1
import json
2
+ import s3fs
2
3
3
4
from notebook .base .handlers import APIHandler
4
5
from notebook .utils import url_path_join
5
- from tornado import web
6
+ from tornado import web , gen
6
7
7
8
from ._version import get_versions
9
+ from .bookstore_config import BookstoreSettings
10
+
11
+ from notebook .base .handlers import IPythonHandler , APIHandler , path_regex
8
12
9
13
version = get_versions ()['version' ]
10
14
15
+ from .s3_paths import s3_path , s3_display_path
16
+
11
17
12
18
class BookstoreVersionHandler (APIHandler ):
13
19
"""Returns the version of bookstore currently running. Used mostly to lay foundations
@@ -19,13 +25,104 @@ def get(self):
19
25
self .finish (json .dumps ({"bookstore" : True , "version" : version }))
20
26
21
27
28
+ # NOTE: We need to ensure that publishing is not configured if bookstore settings are not
29
+ # set. Because of how the APIHandlers cannot be configurable, all we can do is reach into settings
30
+
31
+
32
+ class BookstorePublishHandler (APIHandler ):
33
+ """Publish a notebook to the publish path"""
34
+
35
+ def __init__ (self , * args , ** kwargs ):
36
+ super (APIHandler , self ).__init__ (* args , ** kwargs )
37
+ # create an easy helper to get at our bookstore settings quickly
38
+ self .bookstore_settings = BookstoreSettings (
39
+ config = self .settings ['config' ]['BookstoreSettings' ]
40
+ )
41
+
42
+ self .fs = s3fs .S3FileSystem (
43
+ key = self .bookstore_settings .s3_access_key_id ,
44
+ secret = self .bookstore_settings .s3_secret_access_key ,
45
+ client_kwargs = {
46
+ "endpoint_url" : self .bookstore_settings .s3_endpoint_url ,
47
+ "region_name" : self .bookstore_settings .s3_region_name ,
48
+ },
49
+ config_kwargs = {},
50
+ s3_additional_kwargs = {},
51
+ )
52
+
53
+ @property
54
+ def bucket (self ):
55
+ return self .bookstore_settings .s3_bucket
56
+
57
+ @property
58
+ def prefix (self ):
59
+ return self .bookstore_settings .published_prefix
60
+
61
+ def s3_path (self , path ):
62
+ """compute the s3 path based on the bucket, prefix, and the path to the notebook"""
63
+ return s3_path (self .bucket , self .prefix , path )
64
+
65
+ def _publish (self , model , path ):
66
+ if model ['type' ] != 'notebook' :
67
+ raise web .HTTPError (400 , "bookstore only publishes notebooks" )
68
+ content = model ['content' ]
69
+
70
+ full_s3_path = self .s3_path (path )
71
+
72
+ self .log .info ("Publishing to %s" , s3_display_path (self .bucket , self .prefix , path ))
73
+
74
+ # Likely implementation:
75
+ #
76
+ # with self.fs.open(full_s3_path, mode="wb") as f:
77
+ # f.write(content.encode("utf-8"))
78
+ #
79
+ # However, we need to get back other information for our response
80
+ # Ideally, we'd return back the version id
81
+ #
82
+ # self.status(201)
83
+ # self.finish(json.dumps({"s3path": full_s3_path, "versionID": vID}))
84
+ #
85
+
86
+ # Return 501 - Not Implemented
87
+ # Until we're ready
88
+ self .set_status (501 )
89
+
90
+ @web .authenticated
91
+ @gen .coroutine
92
+ def put (self , path = '' ):
93
+ '''Publish a notebook on a given path. The payload for this directly matches that of the contents API for PUT.
94
+ '''
95
+ if path == '' or path == '/' :
96
+ raise web .HTTPError (400 , "Must have a path to publish to" )
97
+
98
+ model = self .get_json_body ()
99
+
100
+ if model :
101
+ self ._publish (model , path .lstrip ('/' ))
102
+ else :
103
+ raise web .HTTPError (400 , "Cannot publish empty model" )
104
+
105
+
22
106
def load_jupyter_server_extension (nb_app ):
23
107
web_app = nb_app .web_app
24
108
host_pattern = '.*$'
25
- base_bookstore_pattern = url_path_join (
26
- web_app .settings ['base_url' ], '/api/bookstore'
27
- )
109
+ base_bookstore_pattern = url_path_join (web_app .settings ['base_url' ], '/api/bookstore' )
110
+
111
+ # Always enable the version handler
112
+ web_app .add_handlers (host_pattern , [(base_bookstore_pattern , BookstoreVersionHandler )])
113
+
114
+ config = web_app .settings ['config' ]
115
+ bookstore_settings = config .get ("BookstoreSettings" )
28
116
29
- web_app .add_handlers (
30
- host_pattern , [(base_bookstore_pattern , BookstoreVersionHandler )]
31
- )
117
+ if not bookstore_settings :
118
+ nb_app .log .info ("Not enabling bookstore publishing since bookstore endpoint not configured" )
119
+ else :
120
+ web_app .add_handlers (
121
+ host_pattern ,
122
+ [
123
+ (
124
+ url_path_join (base_bookstore_pattern , r"/published%s" % path_regex ),
125
+ BookstorePublishHandler ,
126
+ )
127
+ ],
128
+ )
0 commit comments