diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js
index 21416adfed..24070160cb 100644
--- a/awx/ui/static/js/app.js
+++ b/awx/ui/static/js/app.js
@@ -230,8 +230,8 @@ angular.module('ansible', [
otherwise({redirectTo: '/'});
}])
- .run(['$rootScope', 'CheckLicense', '$location', 'Authorization','LoadBasePaths', 'ViewLicense',
- function($rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense) {
+ .run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization','LoadBasePaths', 'ViewLicense',
+ function($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense) {
LoadBasePaths();
@@ -239,8 +239,8 @@ angular.module('ansible', [
$rootScope.crumbCache = new Array();
$rootScope.$on("$routeChangeStart", function(event, next, current) {
- // Evaluate the token on each navigation request. Redirect to login page when not valid
- if (Authorization.isTokenValid() == false) {
+ // On each navigation request, check that the user is logged in
+ if (Authorization.isUserLoggedIn() == false) {
if ( next.templateUrl != (urlPrefix + 'partials/login.html') ) {
$location.path('/login');
}
@@ -262,8 +262,10 @@ angular.module('ansible', [
}
});
- if (! Authorization.isTokenValid() ) {
+ if (!Authorization.getToken()) {
// When the app first loads, redirect to login page
+ $rootScope.sessionExpired = false;
+ $cookieStore.put('sessionExpired', false);
$location.path('/login');
}
diff --git a/awx/ui/static/js/config.js b/awx/ui/static/js/config.js
index b25166ecf3..d0e9f37dbd 100644
--- a/awx/ui/static/js/config.js
+++ b/awx/ui/static/js/config.js
@@ -9,10 +9,7 @@
*/
var $AnsibleConfig =
-{
- session_timeout: 3600, // cookie expiration in seconds. session will expire after this many
- // seconds of inactivity.
-
+{
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
debug_mode: true, // Enable console logging messages
diff --git a/awx/ui/static/js/controllers/Authentication.js b/awx/ui/static/js/controllers/Authentication.js
index dabfe32ec8..3f0851b790 100644
--- a/awx/ui/static/js/controllers/Authentication.js
+++ b/awx/ui/static/js/controllers/Authentication.js
@@ -10,7 +10,7 @@
'use strict';
-function Authenticate($window, $scope, $rootScope, $location, Authorization, ToggleClass, Alert)
+function Authenticate($cookieStore, $window, $scope, $rootScope, $location, Authorization, ToggleClass, Alert)
{
var setLoginFocus = function() {
$('#login-username').focus();
@@ -18,6 +18,7 @@ function Authenticate($window, $scope, $rootScope, $location, Authorization, Tog
// Display the login dialog
$('#login-modal').modal({ show: true, keyboard: false, backdrop: 'static' });
+
// Set focus to username field
$('#login-modal').on('shown.bs.modal', function() {
setLoginFocus();
@@ -36,18 +37,8 @@ function Authenticate($window, $scope, $rootScope, $location, Authorization, Tog
Authorization.logout();
}
- scope.sessionTimeout = ($AnsibleConfig.session_timeout / 60).toFixed(2);
-
- if ($rootScope.userLoggedIn) {
- // If we're logged in, check for session timeout
- scope.sessionExpired = Authorization.didSessionExpire();
- }
- else {
- scope.sessionExpired = false;
- }
-
- $rootScope.userLoggedIn = false; //hide the logout link. if you got here, you're logged out.
- //gets set back to true by Authorization.setToken().
+ $rootScope.userLoggedIn = false; //hide the logout link. if you got here, you're logged out.
+ $cookieStore.put('userLoggedIn', false); //gets set back to true by Authorization.setToken().
$('#login-password').bind('keypress', function(e) {
var code = (e.keyCode ? e.keyCode : e.which);
@@ -73,16 +64,7 @@ function Authenticate($window, $scope, $rootScope, $location, Authorization, Tog
.success( function(data, status, headers, config) {
$('#login-modal').modal('hide');
token = data.token;
- Authorization.setToken(data.token);
- scope.reset();
-
- // Force request to /organizations to query with the correct token -in the event a new user
- // has logged in.
- var today = new Date();
- today.setTime(today.getTime() + ($AnsibleConfig.session_timeout * 1000));
- $rootScope.token = token;
- $rootScope.userLoggedIn = true;
- $rootScope.token_expire = today.getTime();
+ Authorization.setToken(data.token, data.expires);
// Get all the profile/access info regarding the logged in user
Authorization.getUser()
@@ -126,5 +108,5 @@ function Authenticate($window, $scope, $rootScope, $location, Authorization, Tog
}
}
-Authenticate.$inject = ['$window', '$scope', '$rootScope', '$location', 'Authorization', 'ToggleClass', 'Alert'];
+Authenticate.$inject = ['$cookieStore', '$window', '$scope', '$rootScope', '$location', 'Authorization', 'ToggleClass', 'Alert'];
diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js
index c9039bfbd0..91740aff4c 100644
--- a/awx/ui/static/js/controllers/Credentials.js
+++ b/awx/ui/static/js/controllers/Credentials.js
@@ -29,6 +29,9 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
SelectionInit({ scope: scope, list: list, url: url, returnToCaller: 1 });
+ if (scope.PostRefreshRemove) {
+ scope.PostRefreshRemove();
+ }
scope.PostRefershRemove = scope.$on('PostRefresh', function() {
// After a refresh, populate the organization name on each row
for(var i=0; i < scope.credentials.length; i++) {
diff --git a/awx/ui/static/js/controllers/Organizations.js b/awx/ui/static/js/controllers/Organizations.js
index 0d5ed2e48c..10e85a2bbd 100644
--- a/awx/ui/static/js/controllers/Organizations.js
+++ b/awx/ui/static/js/controllers/Organizations.js
@@ -176,7 +176,7 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
- { hdr: 'Error!', msg: 'Failed to retrieve organization: ' + $routeParams.id + '. GET status: ' + status });
+ { hdr: 'Error!', msg: 'Failed to retrieve organization: ' + $routeParams.id + '. GET status: ' + status });
});
@@ -194,7 +194,7 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, OrganizationForm,
- { hdr: 'Error!', msg: 'Failed to update organization: ' + id + '. PUT status: ' + status });
+ { hdr: 'Error!', msg: 'Failed to update organization: ' + id + '. PUT status: ' + status });
});
};
diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js
index d94c04a956..eab5635b21 100644
--- a/awx/ui/static/js/forms/JobTemplates.js
+++ b/awx/ui/static/js/forms/JobTemplates.js
@@ -54,6 +54,7 @@ angular.module('JobTemplateFormDefinition', [])
addRequired: true,
editRequired: true,
ngClick: 'lookUpInventory()',
+ awRequiredWhen: {variable: "inventoryrequired", init: "true" },
column: 1
},
project: {
@@ -64,6 +65,7 @@ angular.module('JobTemplateFormDefinition', [])
addRequired: true,
editRequired: true,
ngClick: 'lookUpProject()',
+ awRequiredWhen: {variable: "projectrequired", init: "true" },
column: 1
},
playbook: {
@@ -73,6 +75,7 @@ angular.module('JobTemplateFormDefinition', [])
id: 'playbook-select',
addRequired: true,
editRequired: true,
+ awRequiredWhen: {variable: "playbookrequired", init: "true" },
column: 1
},
credential: {
diff --git a/awx/ui/static/js/helpers/refresh-related.js b/awx/ui/static/js/helpers/refresh-related.js
index c6963cd17f..1b6122971e 100644
--- a/awx/ui/static/js/helpers/refresh-related.js
+++ b/awx/ui/static/js/helpers/refresh-related.js
@@ -15,7 +15,7 @@
*/
angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities'])
- .factory('RefreshRelated', ['Alert', 'Rest', function(Alert, Rest) {
+ .factory('RefreshRelated', ['ProcessErrors', 'Rest', function(ProcessErrors, Rest) {
return function(params) {
var scope = params.scope;
@@ -40,7 +40,8 @@ angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities'])
})
.error ( function(data, status, headers, config) {
scope[iterator + 'SearchSpin'] = true;
- Alert('Error!', 'Failed to retrieve related set: ' + set + '. GET returned status: ' + status);
+ ProcessErrors(scope, data, status, null,
+ { hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
});
}
}]);
\ No newline at end of file
diff --git a/awx/ui/static/js/helpers/refresh.js b/awx/ui/static/js/helpers/refresh.js
index 8c6fc0e4ff..6983678a51 100644
--- a/awx/ui/static/js/helpers/refresh.js
+++ b/awx/ui/static/js/helpers/refresh.js
@@ -15,7 +15,7 @@
*/
angular.module('RefreshHelper', ['RestServices', 'Utilities'])
- .factory('Refresh', ['Alert', 'Rest', function(Alert, Rest) {
+ .factory('Refresh', ['ProcessErrors', 'Rest', function(ProcessErrors, Rest) {
return function(params) {
var scope = params.scope;
@@ -37,7 +37,8 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities'])
})
.error ( function(data, status, headers, config) {
scope[iterator + 'SearchSpin'] = false;
- Alert('Error!', 'Failed to retrieve ' + set + '. GET returned status: ' + status);
+ ProcessErrors(scope, data, status, null,
+ { hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
});
}
}]);
\ No newline at end of file
diff --git a/awx/ui/static/js/lists/JobHosts.js b/awx/ui/static/js/lists/JobHosts.js
index 99426aba5a..6db18dbc3c 100644
--- a/awx/ui/static/js/lists/JobHosts.js
+++ b/awx/ui/static/js/lists/JobHosts.js
@@ -13,11 +13,11 @@ angular.module('JobHostDefinition', [])
name: 'jobhosts',
iterator: 'jobhost',
editTitle: 'Job Host Summary',
- index: true,
+ indexShow: 'host_id == null',
hover: true,
fields: {
- job: {
+ id: {
label: 'Job ID',
ngClick: "showJob(\{\{ jobhost.job \}\})",
columnShow: 'host_id !== null',
diff --git a/awx/ui/static/lib/ansible/authenticate.js b/awx/ui/static/lib/ansible/AuthService.js
similarity index 60%
rename from awx/ui/static/lib/ansible/authenticate.js
rename to awx/ui/static/lib/ansible/AuthService.js
index ea3d87c990..c973a3adff 100644
--- a/awx/ui/static/lib/ansible/authenticate.js
+++ b/awx/ui/static/lib/ansible/AuthService.js
@@ -1,67 +1,45 @@
/*********************************************
* Copyright (c) 2013 AnsibleWorks, Inc.
*
- * User authentication functions
+ * AuthService.js
*
+ * User authentication functions
*/
-angular.module('AuthService', ['ngCookies'])
- .factory('Authorization', ['$http', '$rootScope', '$location', '$cookieStore', function($http, $rootScope, $location, $cookieStore) {
+angular.module('AuthService', ['ngCookies', 'Utilities'])
+ .factory('Authorization', ['$http', '$rootScope', '$location', '$cookieStore', 'GetBasePath',
+ function($http, $rootScope, $location, $cookieStore, GetBasePath) {
return {
- setToken: function(token) {
+ setToken: function(token, expires) {
// set the session cookie
- var today = new Date();
- today.setTime(today.getTime() + ($AnsibleConfig.session_timeout * 1000));
$cookieStore.remove('token');
- $cookieStore.remove('token_expire');
+ $cookieStore.remove('token_expires');
+ $cookieStore.remove('userLoggedIn');
$cookieStore.put('token', token);
- $cookieStore.put('token_expire', today.getTime());
+ $cookieStore.put('token_expires', expires);
+ $cookieStore.put('userLoggedIn', true);
+ $cookieStore.put('sessionExpired', false);
$rootScope.token = token;
$rootScope.userLoggedIn = true;
- $rootScope.token_expire = today.getTime();
+ $rootScope.token_expires = expires;
+ $rootScope.sessionExpired = false;
},
- isTokenValid: function() {
- // check if token exists and is not expired
- var response = false;
- var token = ($rootScope.token) ? $rootScope.token : $cookieStore.get('token');
- var token_expire = ($rootScope.token_expire) ? $rootScope.token_expire : $cookieStore.get('token_expire');
- if (token && token_expire) {
- var exp = new Date(token_expire);
- var today = new Date();
- if (today < exp) {
- this.setToken(token); //push expiration into the future while user is active
- response = true;
- }
+ isUserLoggedIn: function() {
+ if ($rootScope.userLoggedIn == undefined) {
+ // Browser refresh may have occurred
+ $rootScope.userLoggedIn = $cookieStore.get('userLoggedIn');
+ $rootScope.sessionExpired = $cookieStore.get('sessionExpired');
}
- return response;
+ return $rootScope.userLoggedIn;
},
- didSessionExpire: function() {
- // use only to test why user was sent to login page.
- var response = false;
- var token_expire = ($rootScope.token_expire) ? $rootScope.token_expire : $cookieStore.get('token_expire');
- if (token_expire) {
- var exp = new Date(token_expire);
- var today = new Date();
- if (exp < today) {
- response = true;
- }
- }
- return response;
- },
-
getToken: function() {
- if ( this.isTokenValid() ) {
- return ($rootScope.token) ? $rootScope.token : $cookieStore.get('token');
- }
- else {
- $location.path('/login');
- }
- },
+ return ($rootScope.token) ? $rootScope.token : $cookieStore.get('token');
+ },
retrieveToken: function(username, password) {
- return $http({ method: 'POST', url: '/api/v1/authtoken/',
+ return $http({ method: 'POST', url: GetBasePath('authtoken'),
data: {"username": username, "password": password} });
},
@@ -70,15 +48,17 @@ angular.module('AuthService', ['ngCookies'])
// should prevent content flash from the prior user.
var scope = angular.element(document.getElementById('main-view')).scope();
scope.$destroy();
- $rootScope.$destroy();
-
+ $rootScope.$destroy();
$cookieStore.remove('accordions');
$cookieStore.remove('token');
$cookieStore.remove('token_expire');
$cookieStore.remove('current_user');
+ $cookieStore.put('userLoggedIn', false);
+ $cookieStore.put('sessionExpired', false);
$rootScope.current_user = {};
$rootScope.license_tested = undefined;
$rootScope.userLoggedIn = false;
+ $rootScope.sessionExpired = false;
$rootScope.token = null;
$rootScope.token_expire = new Date(1970, 0, 1, 0, 0, 0, 0);
},
@@ -86,7 +66,7 @@ angular.module('AuthService', ['ngCookies'])
getLicense: function() {
return $http({
method: 'GET',
- url: '/api/v1/config/',
+ url: GetBasePath('config'),
headers: { 'Authorization': 'Token ' + this.getToken() }
});
},
diff --git a/awx/ui/static/lib/ansible/rest-services.js b/awx/ui/static/lib/ansible/RestServices.js
similarity index 100%
rename from awx/ui/static/lib/ansible/rest-services.js
rename to awx/ui/static/lib/ansible/RestServices.js
diff --git a/awx/ui/static/lib/ansible/utilities.js b/awx/ui/static/lib/ansible/Utilities.js
similarity index 94%
rename from awx/ui/static/lib/ansible/utilities.js
rename to awx/ui/static/lib/ansible/Utilities.js
index 494e291b7a..bf419b193e 100644
--- a/awx/ui/static/lib/ansible/utilities.js
+++ b/awx/ui/static/lib/ansible/Utilities.js
@@ -78,8 +78,14 @@ angular.module('Utilities',[])
}
}])
- .factory('ProcessErrors', ['$log', 'Alert', function($log, Alert) {
+ .factory('ProcessErrors', ['$cookieStore', '$log', '$location', '$rootScope', 'Alert',
+ function($cookieStore, $log, $location, $rootScope, Alert) {
return function(scope, data, status, form, defaultMsg) {
+ if ($AnsibleConfig.debug_mode && console) {
+ console.log('Debug status: ' + status);
+ console.log('Debug data: ');
+ console.log(data);
+ }
if (status == 403) {
var msg = 'The API responded with a 403 Access Denied error. ';
if (data['detail']) {
@@ -90,6 +96,11 @@ angular.module('Utilities',[])
}
Alert(defaultMsg.hdr, msg);
}
+ else if (status == 401 && data.detail && data.detail == 'Token is expired') {
+ $rootScope.sessionExpired = true;
+ $cookieStore.put('sessionExpired', true);
+ $location.path('/login');
+ }
else if (data.non_field_errors) {
Alert('Error!', data.non_field_errors);
}
@@ -250,4 +261,3 @@ angular.module('Utilities',[])
}
}
}]);
-
\ No newline at end of file
diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html
index b00f390717..a9e7123245 100644
--- a/awx/ui/templates/ui/index.html
+++ b/awx/ui/templates/ui/index.html
@@ -25,9 +25,9 @@
{% else %}
-
-
-
+
+
+