##// END OF EJS Templates
move read_only flag to page-level...
MinRK -
Show More
@@ -41,7 +41,7 b' except ImportError:'
41
41
42 @decorator
42 @decorator
43 def not_if_readonly(f, self, *args, **kwargs):
43 def not_if_readonly(f, self, *args, **kwargs):
44 if self.application.ipython_app.read_only:
44 if self.application.read_only:
45 raise web.HTTPError(403, "Notebook server is read-only")
45 raise web.HTTPError(403, "Notebook server is read-only")
46 else:
46 else:
47 return f(self, *args, **kwargs)
47 return f(self, *args, **kwargs)
@@ -57,7 +57,7 b' def authenticate_unless_readonly(f, self, *args, **kwargs):'
57 @web.authenticated
57 @web.authenticated
58 def auth_f(self, *args, **kwargs):
58 def auth_f(self, *args, **kwargs):
59 return f(self, *args, **kwargs)
59 return f(self, *args, **kwargs)
60 if self.application.ipython_app.read_only:
60 if self.application.read_only:
61 return f(self, *args, **kwargs)
61 return f(self, *args, **kwargs)
62 else:
62 else:
63 return auth_f(self, *args, **kwargs)
63 return auth_f(self, *args, **kwargs)
@@ -77,9 +77,20 b' class AuthenticatedHandler(web.RequestHandler):'
77 if user_id is None:
77 if user_id is None:
78 # prevent extra Invalid cookie sig warnings:
78 # prevent extra Invalid cookie sig warnings:
79 self.clear_cookie('username')
79 self.clear_cookie('username')
80 if not self.application.password and not self.application.ipython_app.read_only:
80 if not self.application.password and not self.application.read_only:
81 user_id = 'anonymous'
81 user_id = 'anonymous'
82 return user_id
82 return user_id
83
84 @property
85 def read_only(self):
86 if self.application.read_only:
87 if self.application.password:
88 return self.get_current_user() is None
89 else:
90 return True
91 else:
92 return False
93
83
94
84
95
85 class ProjectDashboardHandler(AuthenticatedHandler):
96 class ProjectDashboardHandler(AuthenticatedHandler):
@@ -90,21 +101,24 b' class ProjectDashboardHandler(AuthenticatedHandler):'
90 project = nbm.notebook_dir
101 project = nbm.notebook_dir
91 self.render(
102 self.render(
92 'projectdashboard.html', project=project,
103 'projectdashboard.html', project=project,
93 base_project_url=u'/', base_kernel_url=u'/'
104 base_project_url=u'/', base_kernel_url=u'/',
105 read_only=self.read_only,
94 )
106 )
95
107
96
108
97 class LoginHandler(AuthenticatedHandler):
109 class LoginHandler(AuthenticatedHandler):
98
110
99 def get(self):
111 def get(self):
100 self.render('login.html', next=self.get_argument('next', default='/'))
112 self.render('login.html',
113 next=self.get_argument('next', default='/'),
114 read_only=self.read_only,
115 )
101
116
102 def post(self):
117 def post(self):
103 pwd = self.get_argument('password', default=u'')
118 pwd = self.get_argument('password', default=u'')
104 if self.application.password and pwd == self.application.password:
119 if self.application.password and pwd == self.application.password:
105 self.set_secure_cookie('username', str(uuid.uuid4()))
120 self.set_secure_cookie('username', str(uuid.uuid4()))
106 url = self.get_argument('next', default='/')
121 self.redirect(self.get_argument('next', default='/'))
107 self.redirect(url)
108
122
109
123
110 class NewHandler(AuthenticatedHandler):
124 class NewHandler(AuthenticatedHandler):
@@ -118,7 +132,8 b' class NewHandler(AuthenticatedHandler):'
118 'notebook.html', project=project,
132 'notebook.html', project=project,
119 notebook_id=notebook_id,
133 notebook_id=notebook_id,
120 base_project_url=u'/', base_kernel_url=u'/',
134 base_project_url=u'/', base_kernel_url=u'/',
121 kill_kernel=False
135 kill_kernel=False,
136 read_only=False,
122 )
137 )
123
138
124
139
@@ -130,11 +145,13 b' class NamedNotebookHandler(AuthenticatedHandler):'
130 project = nbm.notebook_dir
145 project = nbm.notebook_dir
131 if not nbm.notebook_exists(notebook_id):
146 if not nbm.notebook_exists(notebook_id):
132 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
147 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
148
133 self.render(
149 self.render(
134 'notebook.html', project=project,
150 'notebook.html', project=project,
135 notebook_id=notebook_id,
151 notebook_id=notebook_id,
136 base_project_url=u'/', base_kernel_url=u'/',
152 base_project_url=u'/', base_kernel_url=u'/',
137 kill_kernel=False
153 kill_kernel=False,
154 read_only=self.read_only,
138 )
155 )
139
156
140
157
@@ -393,12 +410,6 b' class NotebookRootHandler(AuthenticatedHandler):'
393 @authenticate_unless_readonly
410 @authenticate_unless_readonly
394 def get(self):
411 def get(self):
395
412
396 # communicate read-only via Allow header
397 if self.application.ipython_app.read_only and not self.get_current_user():
398 self.set_header('Allow', 'GET')
399 else:
400 self.set_header('Allow', ', '.join(self.SUPPORTED_METHODS))
401
402 nbm = self.application.notebook_manager
413 nbm = self.application.notebook_manager
403 files = nbm.list_notebooks()
414 files = nbm.list_notebooks()
404 self.finish(jsonapi.dumps(files))
415 self.finish(jsonapi.dumps(files))
@@ -427,12 +438,6 b' class NotebookHandler(AuthenticatedHandler):'
427 format = self.get_argument('format', default='json')
438 format = self.get_argument('format', default='json')
428 last_mod, name, data = nbm.get_notebook(notebook_id, format)
439 last_mod, name, data = nbm.get_notebook(notebook_id, format)
429
440
430 # communicate read-only via Allow header
431 if self.application.ipython_app.read_only and not self.get_current_user():
432 self.set_header('Allow', 'GET')
433 else:
434 self.set_header('Allow', ', '.join(self.SUPPORTED_METHODS))
435
436 if format == u'json':
441 if format == u'json':
437 self.set_header('Content-Type', 'application/json')
442 self.set_header('Content-Type', 'application/json')
438 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
443 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
@@ -105,6 +105,7 b' class NotebookWebApplication(web.Application):'
105 self.log = log
105 self.log = log
106 self.notebook_manager = notebook_manager
106 self.notebook_manager = notebook_manager
107 self.ipython_app = ipython_app
107 self.ipython_app = ipython_app
108 self.read_only = self.ipython_app.read_only
108
109
109
110
110 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
@@ -65,8 +65,10 b' var IPython = (function (IPython) {'
65
65
66 LeftPanel.prototype.create_children = function () {
66 LeftPanel.prototype.create_children = function () {
67 this.notebook_section = new IPython.NotebookSection('div#notebook_section');
67 this.notebook_section = new IPython.NotebookSection('div#notebook_section');
68 this.cell_section = new IPython.CellSection('div#cell_section');
68 if (! IPython.read_only){
69 this.kernel_section = new IPython.KernelSection('div#kernel_section');
69 this.cell_section = new IPython.CellSection('div#cell_section');
70 this.kernel_section = new IPython.KernelSection('div#kernel_section');
71 }
70 this.help_section = new IPython.HelpSection('div#help_section');
72 this.help_section = new IPython.HelpSection('div#help_section');
71 }
73 }
72
74
@@ -14,7 +14,7 b' var IPython = (function (IPython) {'
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16 var Notebook = function (selector) {
16 var Notebook = function (selector) {
17 this.read_only = false;
17 this.read_only = IPython.read_only;
18 this.element = $(selector);
18 this.element = $(selector);
19 this.element.scroll();
19 this.element.scroll();
20 this.element.data("notebook", this);
20 this.element.data("notebook", this);
@@ -979,13 +979,6 b' var IPython = (function (IPython) {'
979
979
980 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
980 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
981 var allowed = xhr.getResponseHeader('Allow');
981 var allowed = xhr.getResponseHeader('Allow');
982 if (allowed && allowed.indexOf('PUT') == -1){
983 this.read_only = true;
984 // unhide login button if it's relevant
985 $('span#login_widget').removeClass('hidden');
986 }else{
987 this.read_only = false;
988 }
989 this.fromJSON(data);
982 this.fromJSON(data);
990 if (this.ncells() === 0) {
983 if (this.ncells() === 0) {
991 this.insert_code_cell_below();
984 this.insert_code_cell_below();
@@ -993,9 +986,7 b' var IPython = (function (IPython) {'
993 IPython.save_widget.status_save();
986 IPython.save_widget.status_save();
994 IPython.save_widget.set_notebook_name(data.metadata.name);
987 IPython.save_widget.set_notebook_name(data.metadata.name);
995 this.dirty = false;
988 this.dirty = false;
996 if (this.read_only) {
989 if (! this.read_only) {
997 this.handle_read_only();
998 }else{
999 this.start_kernel();
990 this.start_kernel();
1000 }
991 }
1001 // fromJSON always selects the last cell inserted. We need to wait
992 // fromJSON always selects the last cell inserted. We need to wait
@@ -1006,16 +997,6 b' var IPython = (function (IPython) {'
1006 }, 50);
997 }, 50);
1007 };
998 };
1008
999
1009
1010 Notebook.prototype.handle_read_only = function(){
1011 IPython.left_panel.collapse();
1012 IPython.save_widget.element.find('button#save_notebook').addClass('hidden');
1013 $('button#new_notebook').addClass('hidden');
1014 $('div#cell_section').addClass('hidden');
1015 $('div#kernel_section').addClass('hidden');
1016 }
1017
1018
1019 IPython.Notebook = Notebook;
1000 IPython.Notebook = Notebook;
1020
1001
1021
1002
@@ -73,15 +73,6 b' var IPython = (function (IPython) {'
73
73
74
74
75 NotebookList.prototype.list_loaded = function (data, status, xhr) {
75 NotebookList.prototype.list_loaded = function (data, status, xhr) {
76 var allowed = xhr.getResponseHeader('Allow');
77 if (allowed && allowed.indexOf('PUT') == -1){
78 this.read_only = true;
79 $('#new_notebook').addClass('hidden');
80 // unhide login button if it's relevant
81 $('span#login_widget').removeClass('hidden');
82 }else{
83 this.read_only = false;
84 }
85 var len = data.length;
76 var len = data.length;
86 // Todo: remove old children
77 // Todo: remove old children
87 for (var i=0; i<len; i++) {
78 for (var i=0; i<len; i++) {
@@ -89,7 +80,7 b' var IPython = (function (IPython) {'
89 var nbname = data[i].name;
80 var nbname = data[i].name;
90 var item = this.new_notebook_item(i);
81 var item = this.new_notebook_item(i);
91 this.add_link(notebook_id, nbname, item);
82 this.add_link(notebook_id, nbname, item);
92 if (!this.read_only){
83 if (!IPython.read_only){
93 // hide delete buttons when readonly
84 // hide delete buttons when readonly
94 this.add_delete_button(item);
85 this.add_delete_button(item);
95 }
86 }
@@ -23,6 +23,7 b' $(document).ready(function () {'
23 }
23 }
24 });
24 });
25 IPython.markdown_converter = new Markdown.Converter();
25 IPython.markdown_converter = new Markdown.Converter();
26 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
26
27
27 $('div#header').addClass('border-box-sizing');
28 $('div#header').addClass('border-box-sizing');
28 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
29 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
@@ -43,6 +44,21 b' $(document).ready(function () {'
43
44
44 // These have display: none in the css file and are made visible here to prevent FLOUC.
45 // These have display: none in the css file and are made visible here to prevent FLOUC.
45 $('div#header').css('display','block');
46 $('div#header').css('display','block');
47
48 if(IPython.read_only){
49 // hide various elements from read-only view
50 IPython.save_widget.element.find('button#save_notebook').addClass('hidden');
51 IPython.quick_help.element.addClass('hidden'); // shortcuts are disabled in read_only
52 $('button#new_notebook').addClass('hidden');
53 $('div#cell_section').addClass('hidden');
54 $('div#kernel_section').addClass('hidden');
55 $('span#login_widget').removeClass('hidden');
56 // left panel starts collapsed, but the collapse must happen after
57 // elements start drawing. Don't draw contents of the panel until
58 // after they are collapsed
59 IPython.left_panel.left_panel_element.css('visibility', 'hidden');
60 }
61
46 $('div#main_app').css('display','block');
62 $('div#main_app').css('display','block');
47
63
48 // Perform these actions after the notebook has been loaded.
64 // Perform these actions after the notebook has been loaded.
@@ -53,6 +69,14 b' $(document).ready(function () {'
53 IPython.save_widget.update_url();
69 IPython.save_widget.update_url();
54 IPython.layout_manager.do_resize();
70 IPython.layout_manager.do_resize();
55 IPython.pager.collapse();
71 IPython.pager.collapse();
72 if(IPython.read_only){
73 // collapse the left panel on read-only
74 IPython.left_panel.collapse();
75 // and finally unhide the panel contents after collapse
76 setTimeout(function(){
77 IPython.left_panel.left_panel_element.css('visibility', 'visible');
78 }, 200)
79 }
56 },100);
80 },100);
57 });
81 });
58
82
@@ -27,8 +27,16 b' $(document).ready(function () {'
27 $('div#left_panel').addClass('box-flex');
27 $('div#left_panel').addClass('box-flex');
28 $('div#right_panel').addClass('box-flex');
28 $('div#right_panel').addClass('box-flex');
29
29
30 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
31
30 IPython.notebook_list = new IPython.NotebookList('div#notebook_list');
32 IPython.notebook_list = new IPython.NotebookList('div#notebook_list');
31 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
33 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
34
35 if (IPython.read_only){
36 $('#new_notebook').addClass('hidden');
37 // unhide login button if it's relevant
38 $('span#login_widget').removeClass('hidden');
39 }
32 IPython.notebook_list.load_list();
40 IPython.notebook_list.load_list();
33
41
34 // These have display: none in the css file and are made visible here to prevent FLOUC.
42 // These have display: none in the css file and are made visible here to prevent FLOUC.
@@ -11,6 +11,8 b''
11 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
11 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
12 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
12 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
13
13
14 <meta name="read_only" content="{{read_only}}"/>
15
14 </head>
16 </head>
15
17
16 <body>
18 <body>
@@ -40,7 +40,8 b''
40 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
40 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
41 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
41 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
42 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
42 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
43
43
44 <meta name="read_only" content="{{read_only}}"/>
44
45
45 </head>
46 </head>
46
47
@@ -12,6 +12,8 b''
12 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
12 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
13 <link rel="stylesheet" href="static/css/projectdashboard.css" type="text/css" />
13 <link rel="stylesheet" href="static/css/projectdashboard.css" type="text/css" />
14
14
15 <meta name="read_only" content="{{read_only}}"/>
16
15 </head>
17 </head>
16
18
17 <body data-project={{project}} data-base-project-url={{base_project_url}}
19 <body data-project={{project}} data-base-project-url={{base_project_url}}
General Comments 0
You need to be logged in to leave comments. Login now