improve user feedback for AJAX authentication
authorLunar <lunar@anargeek.net>
Tue, 14 Feb 2012 19:06:17 +0000 (20:06 +0100)
committerLunar <lunar@anargeek.net>
Fri, 24 Feb 2012 18:43:01 +0000 (19:43 +0100)
We now differenciate between bad credentials and issues arising while
performing the authentication. This allows us to properly notify users
when the IMAP server is not reachable.

lib/coquelicot/app.rb
lib/coquelicot/auth.rb
lib/coquelicot/auth/imap.rb
public/javascripts/coquelicot.auth.simplepass.js
public/javascripts/coquelicot.js

index 38fc100..8a9312d 100644 (file)
@@ -80,16 +80,25 @@ module Coquelicot
 
     post '/authenticate' do
       pass unless request.xhr?
-      unless authenticate(params) then
-        error 403, "Forbidden"
+      begin
+        unless authenticate(params)
+          error 403, "Forbidden"
+        end
+        'OK'
+      rescue Coquelicot::Auth::Error => ex
+        error 503, ex.message
       end
-      'OK'
     end
 
     post '/upload' do
-      unless authenticate(params) then
-        error 403, "Forbidden"
+      begin
+        unless authenticate(params)
+          error 403, "Forbidden"
+        end
+      rescue Coquelicot::Auth::Error => ex
+        error 503, ex.message
       end
+
       if params[:file] then
         tmpfile = params[:file][:tempfile]
         name = params[:file][:filename]
index 3d2298e..278291f 100644 (file)
@@ -13,6 +13,8 @@ module Coquelicot
       end
     end
 
+    class Error < StandardError; end
+
     class AbstractAuthenticator
       def initialize(app)
         @app = app
index a9ddea0..ad403c9 100644 (file)
@@ -7,8 +7,16 @@ module Coquelicot
         imap.login(params[:imap_user], params[:imap_password])
         imap.logout
         true
-      rescue
-        false
+      rescue Errno::ECONNREFUSED
+        raise Coquelicot::Auth::Error.new(
+                  'Unable to connect to IMAP server')
+      rescue NoMethodError => ex
+        if [:imap_server, :imap_port].include? ex.name
+          raise Coquelicot::Auth::Error.new(
+                    "Missing '#{ex.name}' attribute in configuration.")
+        else
+          raise
+        end
       end
     end
   end
index 48967f5..18b2f0f 100644 (file)
@@ -7,9 +7,7 @@ var authentication = {
   focus: function() {
     $('#upload_password').focus();
   },
-  handleAccept: function() { alert('success!'); },
   handleReject: function() {
     $('#upload_password').val('');
   },
-  handleFailure: function(status) { alert('failure!' + status); },
 };
index 6ef4694..2b17d84 100644 (file)
@@ -56,30 +56,41 @@ function authenticate() {
       url: 'authenticate',
       dataType: 'text',
       data: authentication.getData(),
-      complete: function(res, status) {
-        if (status === 'success') {
-          $.each(authentication.getData(), function(key, value) {
-            var hiddenField = $('<input type="hidden" />');
-            hiddenField.attr('name', key);
-            hiddenField.val(value);
-            $('#upload').append(hiddenField);
-          });
-          lb.close();
-          if (authentication.handleAccept) {
-            authentication.handleAccept();
-          }
-        } else if (res.responseText == 'Forbidden') {
-          $('#auth-message').text(i18n.pleaseTryAgain);
-          if (authentication.handleReject) {
-            authentication.handleReject();
-          }
-        } else {
-          $('#auth-message').text(i18n.error + status);
-          if (authentication.handleFailure) {
-            authentication.handleFailure(status);
-          }
+      success: function(data, textStatus, jqXHR) {
+        if (data != 'OK') {
+          /* Mh. Something strange happened. */
+          return;
         }
-      }
+        $.each(authentication.getData(), function(key, value) {
+          var hiddenField = $('<input type="hidden" />');
+          hiddenField.attr('name', key);
+          hiddenField.val(value);
+          $('#upload').append(hiddenField);
+        });
+        lb.close();
+        if (authentication.handleAccept) {
+          authentication.handleAccept();
+        }
+      },
+      error: function(jqXHR, textStatus, errorThrown) {
+        switch (jqXHR.status) {
+          case 403:
+            $('#auth-message').text(i18n.pleaseTryAgain);
+            if (authentication.handleReject) {
+              authentication.handleReject();
+            }
+            return;
+          default:
+            $('#auth-message').
+              empty().
+              append($('<div />').text(i18n.error)).
+              append($('<div />').append($('<strong />').text(errorThrown))).
+              append($('<div />').text(jqXHR.responseText));
+            if (authentication.handleFailure) {
+              authentication.handleFailure(textStatus);
+            }
+        }
+      },
     });
     return false;
   });