##// END OF EJS Templates
use ?download=1 to trigger download in /files/...
Min RK -
Show More
@@ -1,48 +1,49 b''
1 """Serve files directly from the ContentsManager."""
1 """Serve files directly from the ContentsManager."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import os
6 import os
7 import mimetypes
7 import mimetypes
8 import json
8 import json
9 import base64
9 import base64
10
10
11 from tornado import web
11 from tornado import web
12
12
13 from IPython.html.base.handlers import IPythonHandler
13 from IPython.html.base.handlers import IPythonHandler
14
14
15 class FilesHandler(IPythonHandler):
15 class FilesHandler(IPythonHandler):
16 """serve files via ContentsManager"""
16 """serve files via ContentsManager"""
17
17
18 @web.authenticated
18 @web.authenticated
19 def get(self, path):
19 def get(self, path):
20 cm = self.settings['contents_manager']
20 cm = self.settings['contents_manager']
21 if cm.is_hidden(path):
21 if cm.is_hidden(path):
22 self.log.info("Refusing to serve hidden file, via 404 Error")
22 self.log.info("Refusing to serve hidden file, via 404 Error")
23 raise web.HTTPError(404)
23 raise web.HTTPError(404)
24
24
25 path, name = os.path.split(path)
25 path, name = os.path.split(path)
26 model = cm.get_model(name, path)
26 model = cm.get_model(name, path)
27
27
28 if self.get_argument("download", False):
29 self.set_header('Content-Disposition','attachment; filename="%s"' % name)
30
28 if model['type'] == 'notebook':
31 if model['type'] == 'notebook':
29 self.set_header('Content-Type', 'application/json')
32 self.set_header('Content-Type', 'application/json')
30 else:
33 else:
31 cur_mime = mimetypes.guess_type(name)[0]
34 cur_mime = mimetypes.guess_type(name)[0]
32 if cur_mime is not None:
35 if cur_mime is not None:
33 self.set_header('Content-Type', cur_mime)
36 self.set_header('Content-Type', cur_mime)
34
37
35 self.set_header('Content-Disposition','attachment; filename="%s"' % name)
36
37 if model['format'] == 'base64':
38 if model['format'] == 'base64':
38 b64_bytes = model['content'].encode('ascii')
39 b64_bytes = model['content'].encode('ascii')
39 self.write(base64.decodestring(b64_bytes))
40 self.write(base64.decodestring(b64_bytes))
40 elif model['format'] == 'json':
41 elif model['format'] == 'json':
41 self.write(json.dumps(model['content']))
42 self.write(json.dumps(model['content']))
42 else:
43 else:
43 self.write(model['content'])
44 self.write(model['content'])
44 self.flush()
45 self.flush()
45
46
46 default_handlers = [
47 default_handlers = [
47 (r"/files/(.*)", FilesHandler),
48 (r"/files/(.*)", FilesHandler),
48 ] No newline at end of file
49 ]
@@ -1,353 +1,353 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'notebook/js/tour',
8 'notebook/js/tour',
9 'bootstrap',
9 'bootstrap',
10 'moment',
10 'moment',
11 ], function(IPython, $, utils, tour, bootstrap, moment) {
11 ], function(IPython, $, utils, tour, bootstrap, moment) {
12 "use strict";
12 "use strict";
13
13
14 var MenuBar = function (selector, options) {
14 var MenuBar = function (selector, options) {
15 // Constructor
15 // Constructor
16 //
16 //
17 // A MenuBar Class to generate the menubar of IPython notebook
17 // A MenuBar Class to generate the menubar of IPython notebook
18 //
18 //
19 // Parameters:
19 // Parameters:
20 // selector: string
20 // selector: string
21 // options: dictionary
21 // options: dictionary
22 // Dictionary of keyword arguments.
22 // Dictionary of keyword arguments.
23 // notebook: Notebook instance
23 // notebook: Notebook instance
24 // layout_manager: LayoutManager instance
24 // layout_manager: LayoutManager instance
25 // events: $(Events) instance
25 // events: $(Events) instance
26 // save_widget: SaveWidget instance
26 // save_widget: SaveWidget instance
27 // quick_help: QuickHelp instance
27 // quick_help: QuickHelp instance
28 // base_url : string
28 // base_url : string
29 // notebook_path : string
29 // notebook_path : string
30 // notebook_name : string
30 // notebook_name : string
31 options = options || {};
31 options = options || {};
32 this.base_url = options.base_url || utils.get_body_data("baseUrl");
32 this.base_url = options.base_url || utils.get_body_data("baseUrl");
33 this.selector = selector;
33 this.selector = selector;
34 this.notebook = options.notebook;
34 this.notebook = options.notebook;
35 this.layout_manager = options.layout_manager;
35 this.layout_manager = options.layout_manager;
36 this.events = options.events;
36 this.events = options.events;
37 this.save_widget = options.save_widget;
37 this.save_widget = options.save_widget;
38 this.quick_help = options.quick_help;
38 this.quick_help = options.quick_help;
39
39
40 try {
40 try {
41 this.tour = new tour.Tour(this.notebook, this.events);
41 this.tour = new tour.Tour(this.notebook, this.events);
42 } catch (e) {
42 } catch (e) {
43 this.tour = undefined;
43 this.tour = undefined;
44 console.log("Failed to instantiate Notebook Tour", e);
44 console.log("Failed to instantiate Notebook Tour", e);
45 }
45 }
46
46
47 if (this.selector !== undefined) {
47 if (this.selector !== undefined) {
48 this.element = $(selector);
48 this.element = $(selector);
49 this.style();
49 this.style();
50 this.bind_events();
50 this.bind_events();
51 }
51 }
52 };
52 };
53
53
54 // TODO: This has definitively nothing to do with style ...
54 // TODO: This has definitively nothing to do with style ...
55 MenuBar.prototype.style = function () {
55 MenuBar.prototype.style = function () {
56 var that = this;
56 var that = this;
57 this.element.find("li").click(function (event, ui) {
57 this.element.find("li").click(function (event, ui) {
58 // The selected cell loses focus when the menu is entered, so we
58 // The selected cell loses focus when the menu is entered, so we
59 // re-select it upon selection.
59 // re-select it upon selection.
60 var i = that.notebook.get_selected_index();
60 var i = that.notebook.get_selected_index();
61 that.notebook.select(i);
61 that.notebook.select(i);
62 }
62 }
63 );
63 );
64 };
64 };
65
65
66 MenuBar.prototype._nbconvert = function (format, download) {
66 MenuBar.prototype._nbconvert = function (format, download) {
67 download = download || false;
67 download = download || false;
68 var notebook_path = this.notebook.notebook_path;
68 var notebook_path = this.notebook.notebook_path;
69 var notebook_name = this.notebook.notebook_name;
69 var notebook_name = this.notebook.notebook_name;
70 if (this.notebook.dirty) {
70 if (this.notebook.dirty) {
71 this.notebook.save_notebook({async : false});
71 this.notebook.save_notebook({async : false});
72 }
72 }
73 var url = utils.url_join_encode(
73 var url = utils.url_join_encode(
74 this.base_url,
74 this.base_url,
75 'nbconvert',
75 'nbconvert',
76 format,
76 format,
77 notebook_path,
77 notebook_path,
78 notebook_name
78 notebook_name
79 ) + "?download=" + download.toString();
79 ) + "?download=" + download.toString();
80
80
81 window.open(url);
81 window.open(url);
82 };
82 };
83
83
84 MenuBar.prototype.bind_events = function () {
84 MenuBar.prototype.bind_events = function () {
85 // File
85 // File
86 var that = this;
86 var that = this;
87 this.element.find('#new_notebook').click(function () {
87 this.element.find('#new_notebook').click(function () {
88 that.notebook.new_notebook();
88 that.notebook.new_notebook();
89 });
89 });
90 this.element.find('#open_notebook').click(function () {
90 this.element.find('#open_notebook').click(function () {
91 window.open(utils.url_join_encode(
91 window.open(utils.url_join_encode(
92 that.notebook.base_url,
92 that.notebook.base_url,
93 'tree',
93 'tree',
94 that.notebook.notebook_path
94 that.notebook.notebook_path
95 ));
95 ));
96 });
96 });
97 this.element.find('#copy_notebook').click(function () {
97 this.element.find('#copy_notebook').click(function () {
98 that.notebook.copy_notebook();
98 that.notebook.copy_notebook();
99 return false;
99 return false;
100 });
100 });
101 this.element.find('#download_ipynb').click(function () {
101 this.element.find('#download_ipynb').click(function () {
102 var base_url = that.notebook.base_url;
102 var base_url = that.notebook.base_url;
103 var notebook_path = that.notebook.notebook_path;
103 var notebook_path = that.notebook.notebook_path;
104 var notebook_name = that.notebook.notebook_name;
104 var notebook_name = that.notebook.notebook_name;
105 if (that.notebook.dirty) {
105 if (that.notebook.dirty) {
106 that.notebook.save_notebook({async : false});
106 that.notebook.save_notebook({async : false});
107 }
107 }
108
108
109 var url = utils.url_join_encode(
109 var url = utils.url_join_encode(
110 base_url,
110 base_url,
111 'files',
111 'files',
112 notebook_path,
112 notebook_path,
113 notebook_name
113 notebook_name
114 );
114 );
115 window.open(url);
115 window.open(url + '?download=1');
116 });
116 });
117
117
118 this.element.find('#print_preview').click(function () {
118 this.element.find('#print_preview').click(function () {
119 that._nbconvert('html', false);
119 that._nbconvert('html', false);
120 });
120 });
121
121
122 this.element.find('#download_py').click(function () {
122 this.element.find('#download_py').click(function () {
123 that._nbconvert('python', true);
123 that._nbconvert('python', true);
124 });
124 });
125
125
126 this.element.find('#download_html').click(function () {
126 this.element.find('#download_html').click(function () {
127 that._nbconvert('html', true);
127 that._nbconvert('html', true);
128 });
128 });
129
129
130 this.element.find('#download_rst').click(function () {
130 this.element.find('#download_rst').click(function () {
131 that._nbconvert('rst', true);
131 that._nbconvert('rst', true);
132 });
132 });
133
133
134 this.element.find('#download_pdf').click(function () {
134 this.element.find('#download_pdf').click(function () {
135 that._nbconvert('pdf', true);
135 that._nbconvert('pdf', true);
136 });
136 });
137
137
138 this.element.find('#rename_notebook').click(function () {
138 this.element.find('#rename_notebook').click(function () {
139 that.save_widget.rename_notebook({notebook: that.notebook});
139 that.save_widget.rename_notebook({notebook: that.notebook});
140 });
140 });
141 this.element.find('#save_checkpoint').click(function () {
141 this.element.find('#save_checkpoint').click(function () {
142 that.notebook.save_checkpoint();
142 that.notebook.save_checkpoint();
143 });
143 });
144 this.element.find('#restore_checkpoint').click(function () {
144 this.element.find('#restore_checkpoint').click(function () {
145 });
145 });
146 this.element.find('#trust_notebook').click(function () {
146 this.element.find('#trust_notebook').click(function () {
147 that.notebook.trust_notebook();
147 that.notebook.trust_notebook();
148 });
148 });
149 this.events.on('trust_changed.Notebook', function (event, trusted) {
149 this.events.on('trust_changed.Notebook', function (event, trusted) {
150 if (trusted) {
150 if (trusted) {
151 that.element.find('#trust_notebook')
151 that.element.find('#trust_notebook')
152 .addClass("disabled")
152 .addClass("disabled")
153 .find("a").text("Trusted Notebook");
153 .find("a").text("Trusted Notebook");
154 } else {
154 } else {
155 that.element.find('#trust_notebook')
155 that.element.find('#trust_notebook')
156 .removeClass("disabled")
156 .removeClass("disabled")
157 .find("a").text("Trust Notebook");
157 .find("a").text("Trust Notebook");
158 }
158 }
159 });
159 });
160 this.element.find('#kill_and_exit').click(function () {
160 this.element.find('#kill_and_exit').click(function () {
161 var close_window = function () {
161 var close_window = function () {
162 // allow closing of new tabs in Chromium, impossible in FF
162 // allow closing of new tabs in Chromium, impossible in FF
163 window.open('', '_self', '');
163 window.open('', '_self', '');
164 window.close();
164 window.close();
165 };
165 };
166 // finish with close on success or failure
166 // finish with close on success or failure
167 that.notebook.session.delete(close_window, close_window);
167 that.notebook.session.delete(close_window, close_window);
168 });
168 });
169 // Edit
169 // Edit
170 this.element.find('#cut_cell').click(function () {
170 this.element.find('#cut_cell').click(function () {
171 that.notebook.cut_cell();
171 that.notebook.cut_cell();
172 });
172 });
173 this.element.find('#copy_cell').click(function () {
173 this.element.find('#copy_cell').click(function () {
174 that.notebook.copy_cell();
174 that.notebook.copy_cell();
175 });
175 });
176 this.element.find('#delete_cell').click(function () {
176 this.element.find('#delete_cell').click(function () {
177 that.notebook.delete_cell();
177 that.notebook.delete_cell();
178 });
178 });
179 this.element.find('#undelete_cell').click(function () {
179 this.element.find('#undelete_cell').click(function () {
180 that.notebook.undelete_cell();
180 that.notebook.undelete_cell();
181 });
181 });
182 this.element.find('#split_cell').click(function () {
182 this.element.find('#split_cell').click(function () {
183 that.notebook.split_cell();
183 that.notebook.split_cell();
184 });
184 });
185 this.element.find('#merge_cell_above').click(function () {
185 this.element.find('#merge_cell_above').click(function () {
186 that.notebook.merge_cell_above();
186 that.notebook.merge_cell_above();
187 });
187 });
188 this.element.find('#merge_cell_below').click(function () {
188 this.element.find('#merge_cell_below').click(function () {
189 that.notebook.merge_cell_below();
189 that.notebook.merge_cell_below();
190 });
190 });
191 this.element.find('#move_cell_up').click(function () {
191 this.element.find('#move_cell_up').click(function () {
192 that.notebook.move_cell_up();
192 that.notebook.move_cell_up();
193 });
193 });
194 this.element.find('#move_cell_down').click(function () {
194 this.element.find('#move_cell_down').click(function () {
195 that.notebook.move_cell_down();
195 that.notebook.move_cell_down();
196 });
196 });
197 this.element.find('#edit_nb_metadata').click(function () {
197 this.element.find('#edit_nb_metadata').click(function () {
198 that.notebook.edit_metadata({
198 that.notebook.edit_metadata({
199 notebook: that.notebook,
199 notebook: that.notebook,
200 keyboard_manager: that.notebook.keyboard_manager});
200 keyboard_manager: that.notebook.keyboard_manager});
201 });
201 });
202
202
203 // View
203 // View
204 this.element.find('#toggle_header').click(function () {
204 this.element.find('#toggle_header').click(function () {
205 $('div#header').toggle();
205 $('div#header').toggle();
206 that.layout_manager.do_resize();
206 that.layout_manager.do_resize();
207 });
207 });
208 this.element.find('#toggle_toolbar').click(function () {
208 this.element.find('#toggle_toolbar').click(function () {
209 $('div#maintoolbar').toggle();
209 $('div#maintoolbar').toggle();
210 that.layout_manager.do_resize();
210 that.layout_manager.do_resize();
211 });
211 });
212 // Insert
212 // Insert
213 this.element.find('#insert_cell_above').click(function () {
213 this.element.find('#insert_cell_above').click(function () {
214 that.notebook.insert_cell_above('code');
214 that.notebook.insert_cell_above('code');
215 that.notebook.select_prev();
215 that.notebook.select_prev();
216 });
216 });
217 this.element.find('#insert_cell_below').click(function () {
217 this.element.find('#insert_cell_below').click(function () {
218 that.notebook.insert_cell_below('code');
218 that.notebook.insert_cell_below('code');
219 that.notebook.select_next();
219 that.notebook.select_next();
220 });
220 });
221 // Cell
221 // Cell
222 this.element.find('#run_cell').click(function () {
222 this.element.find('#run_cell').click(function () {
223 that.notebook.execute_cell();
223 that.notebook.execute_cell();
224 });
224 });
225 this.element.find('#run_cell_select_below').click(function () {
225 this.element.find('#run_cell_select_below').click(function () {
226 that.notebook.execute_cell_and_select_below();
226 that.notebook.execute_cell_and_select_below();
227 });
227 });
228 this.element.find('#run_cell_insert_below').click(function () {
228 this.element.find('#run_cell_insert_below').click(function () {
229 that.notebook.execute_cell_and_insert_below();
229 that.notebook.execute_cell_and_insert_below();
230 });
230 });
231 this.element.find('#run_all_cells').click(function () {
231 this.element.find('#run_all_cells').click(function () {
232 that.notebook.execute_all_cells();
232 that.notebook.execute_all_cells();
233 });
233 });
234 this.element.find('#run_all_cells_above').click(function () {
234 this.element.find('#run_all_cells_above').click(function () {
235 that.notebook.execute_cells_above();
235 that.notebook.execute_cells_above();
236 });
236 });
237 this.element.find('#run_all_cells_below').click(function () {
237 this.element.find('#run_all_cells_below').click(function () {
238 that.notebook.execute_cells_below();
238 that.notebook.execute_cells_below();
239 });
239 });
240 this.element.find('#to_code').click(function () {
240 this.element.find('#to_code').click(function () {
241 that.notebook.to_code();
241 that.notebook.to_code();
242 });
242 });
243 this.element.find('#to_markdown').click(function () {
243 this.element.find('#to_markdown').click(function () {
244 that.notebook.to_markdown();
244 that.notebook.to_markdown();
245 });
245 });
246 this.element.find('#to_raw').click(function () {
246 this.element.find('#to_raw').click(function () {
247 that.notebook.to_raw();
247 that.notebook.to_raw();
248 });
248 });
249 this.element.find('#to_heading1').click(function () {
249 this.element.find('#to_heading1').click(function () {
250 that.notebook.to_heading(undefined, 1);
250 that.notebook.to_heading(undefined, 1);
251 });
251 });
252 this.element.find('#to_heading2').click(function () {
252 this.element.find('#to_heading2').click(function () {
253 that.notebook.to_heading(undefined, 2);
253 that.notebook.to_heading(undefined, 2);
254 });
254 });
255 this.element.find('#to_heading3').click(function () {
255 this.element.find('#to_heading3').click(function () {
256 that.notebook.to_heading(undefined, 3);
256 that.notebook.to_heading(undefined, 3);
257 });
257 });
258 this.element.find('#to_heading4').click(function () {
258 this.element.find('#to_heading4').click(function () {
259 that.notebook.to_heading(undefined, 4);
259 that.notebook.to_heading(undefined, 4);
260 });
260 });
261 this.element.find('#to_heading5').click(function () {
261 this.element.find('#to_heading5').click(function () {
262 that.notebook.to_heading(undefined, 5);
262 that.notebook.to_heading(undefined, 5);
263 });
263 });
264 this.element.find('#to_heading6').click(function () {
264 this.element.find('#to_heading6').click(function () {
265 that.notebook.to_heading(undefined, 6);
265 that.notebook.to_heading(undefined, 6);
266 });
266 });
267
267
268 this.element.find('#toggle_current_output').click(function () {
268 this.element.find('#toggle_current_output').click(function () {
269 that.notebook.toggle_output();
269 that.notebook.toggle_output();
270 });
270 });
271 this.element.find('#toggle_current_output_scroll').click(function () {
271 this.element.find('#toggle_current_output_scroll').click(function () {
272 that.notebook.toggle_output_scroll();
272 that.notebook.toggle_output_scroll();
273 });
273 });
274 this.element.find('#clear_current_output').click(function () {
274 this.element.find('#clear_current_output').click(function () {
275 that.notebook.clear_output();
275 that.notebook.clear_output();
276 });
276 });
277
277
278 this.element.find('#toggle_all_output').click(function () {
278 this.element.find('#toggle_all_output').click(function () {
279 that.notebook.toggle_all_output();
279 that.notebook.toggle_all_output();
280 });
280 });
281 this.element.find('#toggle_all_output_scroll').click(function () {
281 this.element.find('#toggle_all_output_scroll').click(function () {
282 that.notebook.toggle_all_output_scroll();
282 that.notebook.toggle_all_output_scroll();
283 });
283 });
284 this.element.find('#clear_all_output').click(function () {
284 this.element.find('#clear_all_output').click(function () {
285 that.notebook.clear_all_output();
285 that.notebook.clear_all_output();
286 });
286 });
287
287
288 // Kernel
288 // Kernel
289 this.element.find('#int_kernel').click(function () {
289 this.element.find('#int_kernel').click(function () {
290 that.notebook.kernel.interrupt();
290 that.notebook.kernel.interrupt();
291 });
291 });
292 this.element.find('#restart_kernel').click(function () {
292 this.element.find('#restart_kernel').click(function () {
293 that.notebook.restart_kernel();
293 that.notebook.restart_kernel();
294 });
294 });
295 // Help
295 // Help
296 if (this.tour) {
296 if (this.tour) {
297 this.element.find('#notebook_tour').click(function () {
297 this.element.find('#notebook_tour').click(function () {
298 that.tour.start();
298 that.tour.start();
299 });
299 });
300 } else {
300 } else {
301 this.element.find('#notebook_tour').addClass("disabled");
301 this.element.find('#notebook_tour').addClass("disabled");
302 }
302 }
303 this.element.find('#keyboard_shortcuts').click(function () {
303 this.element.find('#keyboard_shortcuts').click(function () {
304 that.quick_help.show_keyboard_shortcuts();
304 that.quick_help.show_keyboard_shortcuts();
305 });
305 });
306
306
307 this.update_restore_checkpoint(null);
307 this.update_restore_checkpoint(null);
308
308
309 this.events.on('checkpoints_listed.Notebook', function (event, data) {
309 this.events.on('checkpoints_listed.Notebook', function (event, data) {
310 that.update_restore_checkpoint(that.notebook.checkpoints);
310 that.update_restore_checkpoint(that.notebook.checkpoints);
311 });
311 });
312
312
313 this.events.on('checkpoint_created.Notebook', function (event, data) {
313 this.events.on('checkpoint_created.Notebook', function (event, data) {
314 that.update_restore_checkpoint(that.notebook.checkpoints);
314 that.update_restore_checkpoint(that.notebook.checkpoints);
315 });
315 });
316 };
316 };
317
317
318 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
318 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
319 var ul = this.element.find("#restore_checkpoint").find("ul");
319 var ul = this.element.find("#restore_checkpoint").find("ul");
320 ul.empty();
320 ul.empty();
321 if (!checkpoints || checkpoints.length === 0) {
321 if (!checkpoints || checkpoints.length === 0) {
322 ul.append(
322 ul.append(
323 $("<li/>")
323 $("<li/>")
324 .addClass("disabled")
324 .addClass("disabled")
325 .append(
325 .append(
326 $("<a/>")
326 $("<a/>")
327 .text("No checkpoints")
327 .text("No checkpoints")
328 )
328 )
329 );
329 );
330 return;
330 return;
331 }
331 }
332
332
333 var that = this;
333 var that = this;
334 checkpoints.map(function (checkpoint) {
334 checkpoints.map(function (checkpoint) {
335 var d = new Date(checkpoint.last_modified);
335 var d = new Date(checkpoint.last_modified);
336 ul.append(
336 ul.append(
337 $("<li/>").append(
337 $("<li/>").append(
338 $("<a/>")
338 $("<a/>")
339 .attr("href", "#")
339 .attr("href", "#")
340 .text(moment(d).format("LLLL"))
340 .text(moment(d).format("LLLL"))
341 .click(function () {
341 .click(function () {
342 that.notebook.restore_checkpoint_dialog(checkpoint);
342 that.notebook.restore_checkpoint_dialog(checkpoint);
343 })
343 })
344 )
344 )
345 );
345 );
346 });
346 });
347 };
347 };
348
348
349 // Backwards compatability.
349 // Backwards compatability.
350 IPython.MenuBar = MenuBar;
350 IPython.MenuBar = MenuBar;
351
351
352 return {'MenuBar': MenuBar};
352 return {'MenuBar': MenuBar};
353 });
353 });
@@ -1,135 +1,151 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test the /files/ handler."""
2 """Test the /files/ handler."""
3
3
4 import io
4 import io
5 import os
5 import os
6 from unicodedata import normalize
6 from unicodedata import normalize
7
7
8 pjoin = os.path.join
8 pjoin = os.path.join
9
9
10 import requests
10 import requests
11 import json
11 import json
12
12
13 from IPython.nbformat.current import (new_notebook, write, new_worksheet,
13 from IPython.nbformat.current import (new_notebook, write, new_worksheet,
14 new_heading_cell, new_code_cell,
14 new_heading_cell, new_code_cell,
15 new_output)
15 new_output)
16
16
17 from IPython.html.utils import url_path_join
17 from IPython.html.utils import url_path_join
18 from .launchnotebook import NotebookTestBase
18 from .launchnotebook import NotebookTestBase
19 from IPython.utils import py3compat
19 from IPython.utils import py3compat
20
20
21
21
22 class FilesTest(NotebookTestBase):
22 class FilesTest(NotebookTestBase):
23 def test_hidden_files(self):
23 def test_hidden_files(self):
24 not_hidden = [
24 not_hidden = [
25 u'Γ₯ b',
25 u'Γ₯ b',
26 u'Γ₯ b/Γ§. d',
26 u'Γ₯ b/Γ§. d',
27 ]
27 ]
28 hidden = [
28 hidden = [
29 u'.Γ₯ b',
29 u'.Γ₯ b',
30 u'Γ₯ b/.Γ§ d',
30 u'Γ₯ b/.Γ§ d',
31 ]
31 ]
32 dirs = not_hidden + hidden
32 dirs = not_hidden + hidden
33
33
34 nbdir = self.notebook_dir.name
34 nbdir = self.notebook_dir.name
35 for d in dirs:
35 for d in dirs:
36 path = pjoin(nbdir, d.replace('/', os.sep))
36 path = pjoin(nbdir, d.replace('/', os.sep))
37 if not os.path.exists(path):
37 if not os.path.exists(path):
38 os.mkdir(path)
38 os.mkdir(path)
39 with open(pjoin(path, 'foo'), 'w') as f:
39 with open(pjoin(path, 'foo'), 'w') as f:
40 f.write('foo')
40 f.write('foo')
41 with open(pjoin(path, '.foo'), 'w') as f:
41 with open(pjoin(path, '.foo'), 'w') as f:
42 f.write('.foo')
42 f.write('.foo')
43 url = self.base_url()
43 url = self.base_url()
44
44
45 for d in not_hidden:
45 for d in not_hidden:
46 path = pjoin(nbdir, d.replace('/', os.sep))
46 path = pjoin(nbdir, d.replace('/', os.sep))
47 r = requests.get(url_path_join(url, 'files', d, 'foo'))
47 r = requests.get(url_path_join(url, 'files', d, 'foo'))
48 r.raise_for_status()
48 r.raise_for_status()
49 self.assertEqual(r.text, 'foo')
49 self.assertEqual(r.text, 'foo')
50 r = requests.get(url_path_join(url, 'files', d, '.foo'))
50 r = requests.get(url_path_join(url, 'files', d, '.foo'))
51 self.assertEqual(r.status_code, 404)
51 self.assertEqual(r.status_code, 404)
52
52
53 for d in hidden:
53 for d in hidden:
54 path = pjoin(nbdir, d.replace('/', os.sep))
54 path = pjoin(nbdir, d.replace('/', os.sep))
55 for foo in ('foo', '.foo'):
55 for foo in ('foo', '.foo'):
56 r = requests.get(url_path_join(url, 'files', d, foo))
56 r = requests.get(url_path_join(url, 'files', d, foo))
57 self.assertEqual(r.status_code, 404)
57 self.assertEqual(r.status_code, 404)
58
58
59 def test_contents_manager(self):
59 def test_contents_manager(self):
60 "make sure ContentsManager returns right files (ipynb, bin, txt)."
60 "make sure ContentsManager returns right files (ipynb, bin, txt)."
61
61
62 nbdir = self.notebook_dir.name
62 nbdir = self.notebook_dir.name
63 base = self.base_url()
63 base = self.base_url()
64
64
65 nb = new_notebook(name='testnb')
65 nb = new_notebook(name='testnb')
66
66
67 ws = new_worksheet()
67 ws = new_worksheet()
68 nb.worksheets = [ws]
68 nb.worksheets = [ws]
69 ws.cells.append(new_heading_cell(u'Created by test Β³'))
69 ws.cells.append(new_heading_cell(u'Created by test Β³'))
70 cc1 = new_code_cell(input=u'print(2*6)')
70 cc1 = new_code_cell(input=u'print(2*6)')
71 cc1.outputs.append(new_output(output_text=u'12', output_type='stream'))
71 cc1.outputs.append(new_output(output_text=u'12', output_type='stream'))
72 ws.cells.append(cc1)
72 ws.cells.append(cc1)
73
73
74 with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w',
74 with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w',
75 encoding='utf-8') as f:
75 encoding='utf-8') as f:
76 write(nb, f, format='ipynb')
76 write(nb, f, format='ipynb')
77
77
78 with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f:
78 with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f:
79 f.write(b'\xff' + os.urandom(5))
79 f.write(b'\xff' + os.urandom(5))
80 f.close()
80 f.close()
81
81
82 with io.open(pjoin(nbdir, 'test.txt'), 'w') as f:
82 with io.open(pjoin(nbdir, 'test.txt'), 'w') as f:
83 f.write(u'foobar')
83 f.write(u'foobar')
84 f.close()
84 f.close()
85
85
86 r = requests.get(url_path_join(base, 'files', 'testnb.ipynb'))
86 r = requests.get(url_path_join(base, 'files', 'testnb.ipynb'))
87 self.assertEqual(r.status_code, 200)
87 self.assertEqual(r.status_code, 200)
88 self.assertIn('print(2*6)', r.text)
88 self.assertIn('print(2*6)', r.text)
89 json.loads(r.text)
89 json.loads(r.text)
90
90
91 r = requests.get(url_path_join(base, 'files', 'test.bin'))
91 r = requests.get(url_path_join(base, 'files', 'test.bin'))
92 self.assertEqual(r.status_code, 200)
92 self.assertEqual(r.status_code, 200)
93 self.assertEqual(r.headers['content-type'], 'application/octet-stream')
93 self.assertEqual(r.headers['content-type'], 'application/octet-stream')
94 self.assertEqual(r.content[:1], b'\xff')
94 self.assertEqual(r.content[:1], b'\xff')
95 self.assertEqual(len(r.content), 6)
95 self.assertEqual(len(r.content), 6)
96
96
97 r = requests.get(url_path_join(base, 'files', 'test.txt'))
97 r = requests.get(url_path_join(base, 'files', 'test.txt'))
98 self.assertEqual(r.status_code, 200)
98 self.assertEqual(r.status_code, 200)
99 self.assertEqual(r.headers['content-type'], 'text/plain')
99 self.assertEqual(r.headers['content-type'], 'text/plain')
100 self.assertEqual(r.text, 'foobar')
100 self.assertEqual(r.text, 'foobar')
101
102 def test_download(self):
103 nbdir = self.notebook_dir.name
104 base = self.base_url()
105
106 text = 'hello'
107 with open(pjoin(nbdir, 'test.txt'), 'w') as f:
108 f.write(text)
109
110 r = requests.get(url_path_join(base, 'files', 'test.txt'))
111 disposition = r.headers.get('Content-Disposition', '')
112 self.assertNotIn('attachment', disposition)
101
113
114 r = requests.get(url_path_join(base, 'files', 'test.txt') + '?download=1')
115 disposition = r.headers.get('Content-Disposition', '')
116 self.assertIn('attachment', disposition)
117 self.assertIn('filename="test.txt"', disposition)
102
118
103 def test_old_files_redirect(self):
119 def test_old_files_redirect(self):
104 """pre-2.0 'files/' prefixed links are properly redirected"""
120 """pre-2.0 'files/' prefixed links are properly redirected"""
105 nbdir = self.notebook_dir.name
121 nbdir = self.notebook_dir.name
106 base = self.base_url()
122 base = self.base_url()
107
123
108 os.mkdir(pjoin(nbdir, 'files'))
124 os.mkdir(pjoin(nbdir, 'files'))
109 os.makedirs(pjoin(nbdir, 'sub', 'files'))
125 os.makedirs(pjoin(nbdir, 'sub', 'files'))
110
126
111 for prefix in ('', 'sub'):
127 for prefix in ('', 'sub'):
112 with open(pjoin(nbdir, prefix, 'files', 'f1.txt'), 'w') as f:
128 with open(pjoin(nbdir, prefix, 'files', 'f1.txt'), 'w') as f:
113 f.write(prefix + '/files/f1')
129 f.write(prefix + '/files/f1')
114 with open(pjoin(nbdir, prefix, 'files', 'f2.txt'), 'w') as f:
130 with open(pjoin(nbdir, prefix, 'files', 'f2.txt'), 'w') as f:
115 f.write(prefix + '/files/f2')
131 f.write(prefix + '/files/f2')
116 with open(pjoin(nbdir, prefix, 'f2.txt'), 'w') as f:
132 with open(pjoin(nbdir, prefix, 'f2.txt'), 'w') as f:
117 f.write(prefix + '/f2')
133 f.write(prefix + '/f2')
118 with open(pjoin(nbdir, prefix, 'f3.txt'), 'w') as f:
134 with open(pjoin(nbdir, prefix, 'f3.txt'), 'w') as f:
119 f.write(prefix + '/f3')
135 f.write(prefix + '/f3')
120
136
121 url = url_path_join(base, 'notebooks', prefix, 'files', 'f1.txt')
137 url = url_path_join(base, 'notebooks', prefix, 'files', 'f1.txt')
122 r = requests.get(url)
138 r = requests.get(url)
123 self.assertEqual(r.status_code, 200)
139 self.assertEqual(r.status_code, 200)
124 self.assertEqual(r.text, prefix + '/files/f1')
140 self.assertEqual(r.text, prefix + '/files/f1')
125
141
126 url = url_path_join(base, 'notebooks', prefix, 'files', 'f2.txt')
142 url = url_path_join(base, 'notebooks', prefix, 'files', 'f2.txt')
127 r = requests.get(url)
143 r = requests.get(url)
128 self.assertEqual(r.status_code, 200)
144 self.assertEqual(r.status_code, 200)
129 self.assertEqual(r.text, prefix + '/files/f2')
145 self.assertEqual(r.text, prefix + '/files/f2')
130
146
131 url = url_path_join(base, 'notebooks', prefix, 'files', 'f3.txt')
147 url = url_path_join(base, 'notebooks', prefix, 'files', 'f3.txt')
132 r = requests.get(url)
148 r = requests.get(url)
133 self.assertEqual(r.status_code, 200)
149 self.assertEqual(r.status_code, 200)
134 self.assertEqual(r.text, prefix + '/f3')
150 self.assertEqual(r.text, prefix + '/f3')
135
151
General Comments 0
You need to be logged in to leave comments. Login now