Skip to content
This repository

Login/out button cleanups #1079

Merged
merged 7 commits into from over 2 years ago

3 participants

Stefan van der Walt Min RK Fernando Perez
Stefan van der Walt
  • Display a login button when viewing the notebook in read-only mode.
  • On the login page, focus on the password field by default.
  • Correctly style login / logout buttons.
  • In read-only mode, redirect to "/" after logout, not "/login".
Min RK
Owner

The login button should not appear in 'default' mode, where it does exactly nothing. Do you know why your PR disables the hidden logic that was there before?

Min RK
Owner

Also, what should happen in the case where read-only mode is the only one available (no password is set)? In your case, you can enter any password, and login just redirects you to the front page. This suggests that login was successful, but it obviously wasn't, as the login button remains (and login is impossible).

I should think that at the very least, trying to login should always fail, and ideally the login button should be disabled in this case as well.

Stefan van der Walt

@minrk The current logic is already broken; it never shows a login button in read-only mode. The problem is that we only make a distinction between read-only vs. non-read-only modes, whereas there is a third case: read-only but with the option to log in. So maybe we can give the read-only property some more states. I'll have a look at how to best accomplish this.

Stefan van der Walt

OK, I see we do have three states in there: None, True and False. I'll check for these separately.

Min RK
Owner

I think the existence of a non-empty password is the thing that tells you whether login is possible.

Stefan van der Walt

Yes, but we don't want to do that logic inside of the templates, if possible.

Stefan van der Walt

@minrk This is the basic idea I had in mind. There are different ways to implement it (e.g., have read_only return a string instead of True, False, None), but this seems to work for now.

Min RK
Owner

There is actually one more case to handle: no password set, and not read-only. This is by far the most common case, and should not draw any login/logout buttons.

Fernando Perez
Owner

@stefanv, this PR needs a rebase as it's now conflicting. Do you think you'll have time to finish it up before we cut the 0.12 RC? That basically means finish it today...

Stefan van der Walt
Fernando Perez
Owner

ok!

Stefan van der Walt

@fperez @minrk This change should make the logic a lot clearer. There are three states that need to be monitored, each now associated with a method:

  • Was the notebook started with the "read-only" flag (method: read_only)
  • Can the user log in, thereby making the notebook rw (method: login_available)
  • Is the current user logged in? (method: logged_in)

I also removed display logic from the javascript, and moved it to the template. Finally, the password field now receives automatic focus.

Min RK
Owner

Awesome, much cleaner than it was before, and I've tried every combination of being logged in / out having password defined / undefined, and readonly, and it seems to always behave how I expect.

The only thing that didn't seem perfect was the fact that login/logout buttons are still drawn on the login page. If that's an easy fix, go for it, otherwise I'm +1 on merging right now.

Stefan van der Walt

That's a trivial fix. Give me one second.

Stefan van der Walt

@minrk That should do it.

Stefan van der Walt Correctly set read_only meta name for use in javascript. Note that th…
…is has a different meaning than in the Python code: not whether the read-only flag was specified upon launch, but whether the notebook is in read-only mode and input should be disabled.
5fd0e96
Fernando Perez fperez merged commit 2bfc449 into from December 13, 2011
Fernando Perez fperez closed this December 13, 2011
Fernando Perez fperez referenced this pull request from a commit January 10, 2012
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 7 unique commits by 1 author.

Dec 13, 2011
Stefan van der Walt Display login button in read-only mode. 09bb9bd
Stefan van der Walt Redirect to front page upon read-only logout. 8463841
Stefan van der Walt On the login page, focus on the password field. c7b2a07
Stefan van der Walt Improve three-state read-only logic. 5b10f05
Stefan van der Walt Split read-only logic into three functions: read_only, logged_in, and…
… login_available. Move display logic from javascript into templates.
bd48758
Stefan van der Walt Hide top login/logout buttons on login/logout pages. 8326cad
Stefan van der Walt Correctly set read_only meta name for use in javascript. Note that th…
…is has a different meaning than in the Python code: not whether the read-only flag was specified upon launch, but whether the notebook is in read-only mode and input should be disabled.
5fd0e96
This page is out of date. Refresh to see the latest.
53  IPython/frontend/html/notebook/handlers.py
@@ -137,17 +137,32 @@ def get_current_user(self):
137 137
             if not self.application.password and not self.application.read_only:
138 138
                 user_id = 'anonymous'
139 139
         return user_id
140  
-    
  140
+
  141
+    @property
  142
+    def logged_in(self):
  143
+        """Is a user currently logged in?
  144
+
  145
+        """
  146
+        user = self.get_current_user()
  147
+        return (user and not user == 'anonymous')
  148
+
  149
+    @property
  150
+    def login_available(self):
  151
+        """May a user proceed to log in?
  152
+
  153
+        This returns True if login capability is available, irrespective of
  154
+        whether the user is already logged in or not.
  155
+
  156
+        """
  157
+        return bool(self.application.password)
  158
+
141 159
     @property
142 160
     def read_only(self):
143  
-        if self.application.read_only:
144  
-            if self.application.password:
145  
-                return self.get_current_user() is None
146  
-            else:
147  
-                return True
148  
-        else:
149  
-            return False
150  
-    
  161
+        """Is the notebook read-only?
  162
+
  163
+        """
  164
+        return self.application.read_only
  165
+
151 166
     @property
152 167
     def ws_url(self):
153 168
         """websocket url matching the current request
@@ -169,6 +184,8 @@ def get(self):
169 184
             'projectdashboard.html', project=project,
170 185
             base_project_url=u'/', base_kernel_url=u'/',
171 186
             read_only=self.read_only,
  187
+            logged_in=self.logged_in,
  188
+            login_available=self.login_available
172 189
         )
173 190
 
174 191
 
@@ -178,6 +195,8 @@ def _render(self, message=None):
178 195
         self.render('login.html',
179 196
                 next=self.get_argument('next', default='/'),
180 197
                 read_only=self.read_only,
  198
+                logged_in=self.logged_in,
  199
+                login_available=self.login_available,
181 200
                 message=message
182 201
         )
183 202
 
@@ -203,7 +222,17 @@ class LogoutHandler(AuthenticatedHandler):
203 222
 
204 223
     def get(self):
205 224
         self.clear_cookie('username')
206  
-        self.render('logout.html', message={'info': 'Successfully logged out.'})
  225
+        if self.login_available:
  226
+            message = {'info': 'Successfully logged out.'}
  227
+        else:
  228
+            message = {'warning': 'Cannot log out.  Notebook authentication '
  229
+                       'is disabled.'}
  230
+
  231
+        self.render('logout.html',
  232
+                    read_only=self.read_only,
  233
+                    logged_in=self.logged_in,
  234
+                    login_available=self.login_available,
  235
+                    message=message)
207 236
 
208 237
 
209 238
 class NewHandler(AuthenticatedHandler):
@@ -219,6 +248,8 @@ def get(self):
219 248
             base_project_url=u'/', base_kernel_url=u'/',
220 249
             kill_kernel=False,
221 250
             read_only=False,
  251
+            logged_in=self.logged_in,
  252
+            login_available=self.login_available,
222 253
             mathjax_url=self.application.ipython_app.mathjax_url,
223 254
         )
224 255
 
@@ -238,6 +269,8 @@ def get(self, notebook_id):
238 269
             base_project_url=u'/', base_kernel_url=u'/',
239 270
             kill_kernel=False,
240 271
             read_only=self.read_only,
  272
+            logged_in=self.logged_in,
  273
+            login_available=self.login_available,
241 274
             mathjax_url=self.application.ipython_app.mathjax_url,
242 275
         )
243 276
 
4  IPython/frontend/html/notebook/static/js/loginwidget.js
@@ -22,12 +22,16 @@ var IPython = (function (IPython) {
22 22
 
23 23
     LoginWidget.prototype.style = function () {
24 24
         this.element.find('button#logout').button();
  25
+        this.element.find('button#login').button();
25 26
     };
26 27
     LoginWidget.prototype.bind_events = function () {
27 28
         var that = this;
28 29
         this.element.find("button#logout").click(function () {
29 30
             window.location = "/logout";
30 31
         });
  32
+        this.element.find("button#login").click(function () {
  33
+            window.location = "/login";
  34
+        });
31 35
     };
32 36
 
33 37
     // Set module variables
11  IPython/frontend/html/notebook/static/js/projectdashboardmain.js
@@ -28,18 +28,9 @@ $(document).ready(function () {
28 28
     $('div#right_panel').addClass('box-flex');
29 29
 
30 30
     IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
31  
-    
32 31
     IPython.notebook_list = new IPython.NotebookList('div#notebook_list');
33 32
     IPython.login_widget = new IPython.LoginWidget('span#login_widget');
34  
-    
35  
-    if (IPython.read_only){
36  
-        // unhide login button if it's relevant
37  
-        $('span#login_widget').removeClass('hidden');
38  
-        $('#drag_info').remove();
39  
-    } else {
40  
-        $('#new_notebook').removeClass('hidden');
41  
-        $('#drag_info').removeClass('hidden');
42  
-    }
  33
+
43 34
     IPython.notebook_list.load_list();
44 35
 
45 36
     // These have display: none in the css file and are made visible here to prevent FLOUC.
18  IPython/frontend/html/notebook/templates/layout.html
@@ -22,11 +22,19 @@
22 22
 
23 23
 <div id="header">
24 24
     <span id="ipython_notebook"><h1><img src='static/ipynblogo.png' alt='IPython Notebook'/></h1></span>
25  
-    <span id="login_widget">
26  
-      {% if current_user and current_user != 'anonymous' %}
27  
-        <button id="logout">Logout</button>
28  
-      {% end %}
29  
-    </span>
  25
+
  26
+    {% block login_widget %}
  27
+
  28
+      <span id="login_widget">
  29
+        {% if logged_in %}
  30
+          <button id="logout">Logout</button>
  31
+        {% elif login_available and not logged_in %}
  32
+          <button id="login">Login</button>
  33
+        {% end %}
  34
+      </span>
  35
+
  36
+    {% end %}
  37
+
30 38
     {% block header %}
31 39
     {% end %}
32 40
 </div>
20  IPython/frontend/html/notebook/templates/login.html
... ...
@@ -1,8 +1,26 @@
1 1
 {% extends layout.html %}
2 2
 
3 3
 {% block content_panel %}
  4
+
  5
+    {% if login_available %}
  6
+
4 7
     <form action="/login?next={{url_escape(next)}}" method="post">
5  
-        Password: <input type="password" name="password">
  8
+        Password: <input type="password" name="password" id="focus">
6 9
         <input type="submit" value="Sign in" id="signin">
7 10
     </form>
  11
+
  12
+    {% end %}
  13
+
  14
+{% end %}
  15
+
  16
+{% block login_widget %}
  17
+{% end %}
  18
+
  19
+{% block script %}
  20
+<script type="text/javascript">
  21
+  $(document).ready(function() {
  22
+    IPython.login_widget = new IPython.LoginWidget('span#login_widget');
  23
+    $('#focus').focus();
  24
+  });
  25
+</script>
8 26
 {% end %}
25  IPython/frontend/html/notebook/templates/logout.html
... ...
@@ -1,5 +1,28 @@
1 1
 {% extends layout.html %}
2 2
 
3 3
 {% block content_panel %}
4  
-Proceed to the <a href="/login">login page</a>.
  4
+  <ul>
  5
+    {% if read_only or not login_available %}
  6
+
  7
+    Proceed to the <a href="/">list of notebooks</a>.</li>
  8
+
  9
+    {% else %}
  10
+
  11
+    Proceed to the <a href="/login">login page</a>.</li>
  12
+
  13
+    {% end %}
  14
+
  15
+  </ul>
  16
+
  17
+{% end %}
  18
+
  19
+{% block login_widget %}
  20
+{% end %}
  21
+
  22
+{% block script %}
  23
+<script type="text/javascript">
  24
+  $(document).ready(function() {
  25
+    IPython.login_widget = new IPython.LoginWidget('span#login_widget');
  26
+  });
  27
+</script>
5 28
 {% end %}
10  IPython/frontend/html/notebook/templates/notebook.html
@@ -29,8 +29,10 @@
29 29
     <link rel="stylesheet" href="static/css/base.css" type="text/css" />
30 30
     <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
31 31
     <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
32  
-    
33  
-    <meta name="read_only" content="{{read_only}}"/>
  32
+
  33
+    {% comment  In the notebook, the read-only flag is used to determine %}
  34
+    {% comment  whether to hide the side panels and switch off input %}
  35
+    <meta name="read_only" content="{{read_only and not logged_in}}"/>
34 36
 
35 37
 </head>
36 38
 
@@ -52,8 +54,10 @@
52 54
     <span id="login_widget">
53 55
       {% comment  This is a temporary workaround to hide the logout button %}
54 56
       {% comment  when appropriate until notebook.html is templated %}
55  
-      {% if current_user and current_user != 'anonymous' %}
  57
+      {% if logged_in %}
56 58
         <button id="logout">Logout</button>
  59
+      {% elif not logged_in and login_available %}
  60
+        <button id="login">Login</button>
57 61
       {% end %}
58 62
     </span>
59 63
 
11  IPython/frontend/html/notebook/templates/projectdashboard.html
@@ -19,12 +19,19 @@
19 19
 {% end %}
20 20
 
21 21
 {% block content_panel %}
  22
+    {% if logged_in or not read_only %}
  23
+
22 24
     <div id="content_toolbar">
23  
-        <span id="drag_info" class="hidden">Drag files onto the list to import notebooks.</span>
  25
+        <span id="drag_info">Drag files onto the list to import
  26
+        notebooks.</span>
  27
+
24 28
         <span id="notebooks_buttons">
25  
-            <button id="new_notebook" class="hidden">New Notebook</button>
  29
+          <button id="new_notebook">New Notebook</button>
26 30
         </span>
27 31
     </div>
  32
+
  33
+    {% end %}
  34
+
28 35
     <div id="notebook_list">
29 36
         <div id="project_name"><h2>{{project}}</h2></div>
30 37
     </div>
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.