diff --git a/Changelog.md b/Changelog.md index 243d18d1e..9fe538216 100644 --- a/Changelog.md +++ b/Changelog.md @@ -88,6 +88,7 @@ With the port to Bootstrap 3, app/views/terms/default.haml has a new structure. ## Refactor ## Bug fixes +* Redirect to sign in page when a background request fails with 401 [#6496](https://github.com/diaspora/diaspora/pull/6496) ## Features diff --git a/app/assets/javascripts/app/app.js b/app/assets/javascripts/app/app.js index 4127b1225..93b0f65e3 100644 --- a/app/assets/javascripts/app/app.js +++ b/app/assets/javascripts/app/app.js @@ -52,6 +52,7 @@ var app = { this.setupGlobalViews(); this.setupDisabledLinks(); this.setupForms(); + this.setupAjaxErrorRedirect(); }, hasPreload : function(prop) { @@ -148,6 +149,22 @@ var app = { $(this).clearForm(); $(this).focusout(); }); + }, + + setupAjaxErrorRedirect: function() { + var self = this; + // Binds the global ajax event. To prevent this, add + // preventGlobalErrorHandling: true + // to the settings of your ajax calls + $(document).ajaxError(function(evt, jqxhr, settings) { + if(jqxhr.status === 401 && !settings.preventGlobalErrorHandling) { + self._changeLocation(Routes.newUserSession()); + } + }); + }, + + _changeLocation: function(href) { + window.location.assign(href); } }; diff --git a/spec/javascripts/app/app_spec.js b/spec/javascripts/app/app_spec.js index 84f4a72f3..bbdcae351 100644 --- a/spec/javascripts/app/app_spec.js +++ b/spec/javascripts/app/app_spec.js @@ -9,6 +9,7 @@ describe("app", function() { spyOn(app, "setupGlobalViews"); spyOn(app, "setupDisabledLinks"); spyOn(app, "setupForms"); + spyOn(app, "setupAjaxErrorRedirect"); app.initialize(); @@ -20,6 +21,7 @@ describe("app", function() { expect(app.setupGlobalViews).toHaveBeenCalled(); expect(app.setupDisabledLinks).toHaveBeenCalled(); expect(app.setupForms).toHaveBeenCalled(); + expect(app.setupAjaxErrorRedirect).toHaveBeenCalled(); }); }); @@ -44,4 +46,47 @@ describe("app", function() { expect($.fn.placeholder.calls.mostRecent().object.selector).toBe("input, textarea"); }); }); + + describe("setupAjaxErrorRedirect", function() { + it("redirects to /users/sign_in on 401 ajax responses", function() { + spyOn(app, "_changeLocation"); + $.ajax("/test"); + jasmine.Ajax.requests.mostRecent().respondWith({status: 401}); + expect(app._changeLocation).toHaveBeenCalledWith("/users/sign_in"); + }); + + it("doesn't redirect on other responses", function() { + spyOn(app, "_changeLocation"); + + [200, 201, 400, 404, 500].forEach(function(code) { + $.ajax("/test"); + jasmine.Ajax.requests.mostRecent().respondWith({status: code}); + expect(app._changeLocation).not.toHaveBeenCalled(); + }); + }); + + it("doesn't redirect when error handling is suppressed", function() { + spyOn(app, "_changeLocation"); + $.ajax("/test", {preventGlobalErrorHandling: true}); + jasmine.Ajax.requests.mostRecent().respondWith({status: 401}); + expect(app._changeLocation).not.toHaveBeenCalled(); + + $.ajax("/test", {preventGlobalErrorHandling: false}); + jasmine.Ajax.requests.mostRecent().respondWith({status: 401}); + expect(app._changeLocation).toHaveBeenCalledWith("/users/sign_in"); + }); + + it("doesn't redirect when global ajax events are disabled", function() { + spyOn(app, "_changeLocation"); + $.ajaxSetup({global: false}); + $.ajax("/test"); + jasmine.Ajax.requests.mostRecent().respondWith({status: 401}); + expect(app._changeLocation).not.toHaveBeenCalled(); + + $.ajaxSetup({global: true}); + $.ajax("/test"); + jasmine.Ajax.requests.mostRecent().respondWith({status: 401}); + expect(app._changeLocation).toHaveBeenCalledWith("/users/sign_in"); + }); + }); });