From 754c1ea331a03a4ca4f76c8dd810370f6166b96a Mon Sep 17 00:00:00 2001
From: Mark McDowall <markus.mcd5@gmail.com>
Date: Tue, 3 Feb 2015 08:37:42 -0800
Subject: [PATCH] Logout button for forms Auth and fix UrlBase redirects

---
 ...LoginModule.cs => AuthenticationModule.cs} | 13 ++++++++++--
 .../Authentication/EnableAuthInNancy.cs       |  2 +-
 src/NzbDrone.Api/NzbDrone.Api.csproj          |  2 +-
 src/UI/System/SystemLayout.js                 | 21 ++++++++++++-------
 src/UI/System/SystemLayoutTemplate.hbs        |  8 ++++++-
 5 files changed, 33 insertions(+), 13 deletions(-)
 rename src/NzbDrone.Api/Authentication/{LoginModule.cs => AuthenticationModule.cs} (65%)

diff --git a/src/NzbDrone.Api/Authentication/LoginModule.cs b/src/NzbDrone.Api/Authentication/AuthenticationModule.cs
similarity index 65%
rename from src/NzbDrone.Api/Authentication/LoginModule.cs
rename to src/NzbDrone.Api/Authentication/AuthenticationModule.cs
index e1de88026..ac87b5f0d 100644
--- a/src/NzbDrone.Api/Authentication/LoginModule.cs
+++ b/src/NzbDrone.Api/Authentication/AuthenticationModule.cs
@@ -4,17 +4,21 @@ using Nancy.Authentication.Forms;
 using Nancy.Extensions;
 using Nancy.ModelBinding;
 using NzbDrone.Core.Authentication;
+using NzbDrone.Core.Configuration;
 
 namespace NzbDrone.Api.Authentication
 {
-    public class LoginModule : NancyModule
+    public class AuthenticationModule : NancyModule
     {
         private readonly IUserService _userService;
+        private readonly IConfigFileProvider _configFileProvider;
 
-        public LoginModule(IUserService userService)
+        public AuthenticationModule(IUserService userService, IConfigFileProvider configFileProvider)
         {
             _userService = userService;
+            _configFileProvider = configFileProvider;
             Post["/login"] = x => Login(this.Bind<LoginResource>());
+            Get["/logout"] = x => Logout();
         }
 
         private Response Login(LoginResource resource)
@@ -35,5 +39,10 @@ namespace NzbDrone.Api.Authentication
 
             return this.LoginAndRedirect(user.Identifier, expiry);
         }
+
+        private Response Logout()
+        {
+            return this.LogoutAndRedirect(_configFileProvider.UrlBase + "/");
+        }
     }
 }
diff --git a/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs b/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs
index 6c982119c..84582904e 100644
--- a/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs
+++ b/src/NzbDrone.Api/Authentication/EnableAuthInNancy.cs
@@ -64,7 +64,7 @@ namespace NzbDrone.Api.Authentication
 
             FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration
             {
-                RedirectUrl = "~/login",
+                RedirectUrl = _configFileProvider.UrlBase + "/login",
                 UserMapper = _authenticationService,
                 CryptographyConfiguration = cryptographyConfiguration
             });
diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj
index 5a98e275c..916b5a631 100644
--- a/src/NzbDrone.Api/NzbDrone.Api.csproj
+++ b/src/NzbDrone.Api/NzbDrone.Api.csproj
@@ -83,7 +83,7 @@
     </Compile>
     <Compile Include="Authentication\AuthenticationService.cs" />
     <Compile Include="Authentication\EnableAuthInNancy.cs" />
-    <Compile Include="Authentication\LoginModule.cs" />
+    <Compile Include="Authentication\AuthenticationModule.cs" />
     <Compile Include="Authentication\LoginResource.cs" />
     <Compile Include="Authentication\NzbDroneUser.cs" />
     <Compile Include="Blacklist\BlacklistModule.cs" />
diff --git a/src/UI/System/SystemLayout.js b/src/UI/System/SystemLayout.js
index 7eb243301..cdb4e680a 100644
--- a/src/UI/System/SystemLayout.js
+++ b/src/UI/System/SystemLayout.js
@@ -1,4 +1,4 @@
-var $ = require('jquery');
+var $ = require('jquery');
 var Backbone = require('backbone');
 var Marionette = require('marionette');
 var SystemInfoLayout = require('./Info/SystemInfoLayout');
@@ -7,6 +7,7 @@ var UpdateLayout = require('./Update/UpdateLayout');
 var BackupLayout = require('./Backup/BackupLayout');
 var TaskLayout = require('./Task/TaskLayout');
 var Messenger = require('../Shared/Messenger');
+var StatusModel = require('./StatusModel');
 
 module.exports = Marionette.Layout.extend({
     template     : 'System/SystemLayoutTemplate',
@@ -25,18 +26,22 @@ module.exports = Marionette.Layout.extend({
         tasksTab   : '.x-tasks-tab'
     },
     events       : {
-        "click .x-info-tab"    : '_showInfo',
-        "click .x-logs-tab"    : '_showLogs',
-        "click .x-updates-tab" : '_showUpdates',
-        "click .x-backup-tab"  : '_showBackup',
-        "click .x-tasks-tab"   : '_showTasks',
-        "click .x-shutdown"    : '_shutdown',
-        "click .x-restart"     : '_restart'
+        'click .x-info-tab'    : '_showInfo',
+        'click .x-logs-tab'    : '_showLogs',
+        'click .x-updates-tab' : '_showUpdates',
+        'click .x-backup-tab'  : '_showBackup',
+        'click .x-tasks-tab'   : '_showTasks',
+        'click .x-shutdown'    : '_shutdown',
+        'click .x-restart'     : '_restart'
     },
     initialize   : function(options){
         if(options.action) {
             this.action = options.action.toLowerCase();
         }
+
+        this.templateHelpers = {
+            authentication : StatusModel.get('authentication')
+        };
     },
     onShow       : function(){
         switch (this.action) {
diff --git a/src/UI/System/SystemLayoutTemplate.hbs b/src/UI/System/SystemLayoutTemplate.hbs
index a3e24f76b..a14338353 100644
--- a/src/UI/System/SystemLayoutTemplate.hbs
+++ b/src/UI/System/SystemLayoutTemplate.hbs
@@ -1,4 +1,4 @@
-<ul class="nav nav-tabs">
+<ul class="nav nav-tabs">
     <li><a href="#info" class="x-info-tab no-router">Info</a></li>
     <li><a href="#logs" class="x-logs-tab no-router">Logs</a></li>
     <li><a href="#updates" class="x-updates-tab no-router">Updates</a></li>
@@ -12,6 +12,12 @@
             <button class="btn btn-default btn-icon-only x-restart" title="Restart" data-container="body">
                 <i class="icon-nd-restart"></i>
             </button>
+
+            {{#if_eq authentication compare="forms"}}
+            <a href="{{UrlBase}}/logout" class="btn btn-default btn-icon-only" title="Logout" data-container="body">
+                <i class="icon-lock"></i>
+            </a>
+            {{/if_eq}}
         </div>
     </li>
 </ul>