Merge branch 'release_2.4.0' into devel

* release_2.4.0: (70 commits)
  Disallow changing a users password for social auth
  bump django-radius to include new license
  Change Jenkins server references from IP to DNS name
  Social auth and SSO updates:
  allow multi-org expired licenses to delete orgs
  Add social log messages to tower's log on error
  Update default scopes requested for github social auth.
  Switch to matburt's fork for python social auth
  Emit a warning for unmapped SAML paramters
  Fix up some SAML issues
  Remove `environment` play stmt
  Use correct aw_repo_url when building packer
  Add missing libxmlsec1 openssl dependency for ubuntu
  adds socket tests
  added git pre commit hook to run flake8
  fixes remove_instance error
  null pointer exception
  Resolve issue on precise keeping old debs around
  Attach handlers to django_auth_ldap
  Attach handlers to django_auth_ldap
  ...
This commit is contained in:
Matthew Jones
2015-11-16 15:12:37 -05:00
62 changed files with 1334 additions and 537 deletions

View File

@@ -1,7 +1,7 @@
<div id="about-dialog-body">
<div class="row">
<div class="col-xs-12 col-sm-5">
<div class="col-xs-12 col-sm-5 About-cowsay">
<div style="width: 340px; margin: 0 auto;">
<pre id="cowsay">
________________
@@ -19,10 +19,11 @@
<div class="col-xs-12 col-sm-7 text-center">
<img id="about-modal-titlelogo" src="/static/assets/ansible_tower_logo_minimalc.png"><br>
<p>Copyright 2015. All rights reserved.</p>
<p>Ansible and Ansible Tower are registered trademarks of Ansible, Inc.</p>
<p>Ansible and Ansible Tower are registered trademarks of Red Hat, Inc.</p>
<br>
<img class="About-redhat" src="/static/assets/redhat_ansible_lockup.png">
<br>
<p>Visit <a href="http://www.ansible.com" target="_blank">Ansible.com</a> for more information.</p>
<br>
<p><span id='about-modal-subscription'></span></p>
</div>
</div>

View File

@@ -0,0 +1,14 @@
/** @define About */
.About {
height: 309px !important;
}
.About-cowsay {
margin-top: 30px;
}
.About-redhat {
max-width: 100%;
margin-top: -61px;
margin-bottom: -33px;
}

View File

@@ -837,9 +837,9 @@ var tower = angular.module('Tower', [
}]);
}])
.run(['$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'HideStream', 'Socket',
.run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'HideStream', 'Socket',
'LoadConfig', 'Store', 'ShowSocketHelp', 'AboutAnsibleHelp', 'pendoService',
function ($compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, HideStream, Socket,
function ($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, HideStream, Socket,
LoadConfig, Store, ShowSocketHelp, AboutAnsibleHelp, pendoService) {
@@ -950,7 +950,8 @@ var tower = angular.module('Tower', [
control_socket.init();
control_socket.on("limit_reached", function(data) {
$log.debug(data.reason);
Timer.expireSession('session_limit');
$rootScope.sessionTimer.expireSession('session_limit');
$location.url('/login');
});
}
openSocket();
@@ -999,7 +1000,7 @@ var tower = angular.module('Tower', [
// gets here on timeout
if (next.templateUrl !== (urlPrefix + 'login/loginBackDrop.partial.html')) {
$rootScope.sessionTimer.expireSession('idle');
if (sock) {
if (sock&& sock.socket && sock.socket.socket) {
sock.socket.socket.disconnect();
}
$location.path('/login');
@@ -1026,9 +1027,11 @@ var tower = angular.module('Tower', [
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
// when the user refreshes we want to open the socket, except if the user is on the login page, which should happen after the user logs in (see the AuthService module for that call to OpenSocket)
if(!_.contains($location.$$url, '/login')){
$rootScope.sessionTimer = Timer.init();
$rootScope.$emit('OpenSocket');
pendoService.issuePendoIdentity();
Timer.init().then(function(timer){
$rootScope.sessionTimer = timer;
$rootScope.$emit('OpenSocket');
pendoService.issuePendoIdentity();
});
}
}
@@ -1063,8 +1066,8 @@ var tower = angular.module('Tower', [
if (!$AnsibleConfig) {
// there may be time lag when loading the config file, so temporarily use what's in local storage
$AnsibleConfig = Store('AnsibleConfig');
// create a promise that will resolve when $AnsibleConfig is loaded
$rootScope.loginConfig = $q.defer();
}
//the authorization controller redirects to the home page automatcially if there is no last path defined. in order to override

View File

@@ -13,7 +13,7 @@
export function JobDetailController ($location, $rootScope, $filter, $scope, $compile, $routeParams, $log, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest,
ProcessErrors, SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, LoadHostSummary, ReloadHostSummaryList, JobIsFinished, SetTaskStyles, DigestEvent,
UpdateDOM, EventViewer, DeleteJob, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices) {
UpdateDOM, EventViewer, DeleteJob, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices, fieldChoices, fieldLabels) {
ClearScope();
@@ -27,11 +27,33 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
scope.plays = [];
scope.previousTaskFailed = false;
scope.$watch('job_status', function(job_status) {
if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") {
scope.previousTaskFailed = true;
var taskObj = JSON.parse(job_status.explanation.substring(job_status.explanation.split(":")[0].length + 1));
job_status.explanation = job_status.explanation.split(":")[0] + ". ";
job_status.explanation += "<code>" + taskObj.task_type + "-" + taskObj.task_id + " failed for " + taskObj.task_name + "</code>"
// return a promise from the options request with the permission type choices (including adhoc) as a param
var fieldChoice = fieldChoices({
scope: $scope,
url: 'api/v1/unified_jobs/',
field: 'type'
});
// manipulate the choices from the options request to be set on
// scope and be usable by the list form
fieldChoice.then(function (choices) {
choices =
fieldLabels({
choices: choices
});
scope.explanation_fail_type = choices[taskObj.job_type];
scope.explanation_fail_name = taskObj.job_name;
scope.explanation_fail_id = taskObj.job_id;
scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with ID " + scope.explanation_fail_id + ".";
});
} else {
scope.previousTaskFailed = false;
}
}, true);
@@ -649,61 +671,6 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
});
if (scope.removeGetCredentialNames) {
scope.removeGetCredentialNames();
}
scope.removeGetCredentialNames = scope.$on('GetCredentialNames', function(e, data) {
var url;
if (data.credential) {
url = GetBasePath('credentials') + data.credential + '/';
Rest.setUrl(url);
Rest.get()
.success( function(data) {
scope.credential_name = data.name;
})
.error( function(data, status) {
scope.credential_name = '';
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}
if (data.cloud_credential) {
url = GetBasePath('credentials') + data.cloud_credential + '/';
Rest.setUrl(url);
Rest.get()
.success( function(data) {
scope.cloud_credential_name = data.name;
})
.error( function(data, status) {
scope.credential_name = '';
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}
});
if (scope.removeGetCreatedByNames) {
scope.removeGetCreatedByNames();
}
scope.removeGetCreatedByNames = scope.$on('GetCreatedByNames', function(e, data) {
var url;
data = data.slice(0, data.length-1);
data = data.slice(data.lastIndexOf('/')+1, data.length);
url = GetBasePath('users') + data + '/';
scope.users_url = '/#/users/' + data;
Rest.setUrl(url);
Rest.get()
.success( function(data) {
scope.created_by = data.username;
})
.error( function(data, status) {
scope.credential_name = '';
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
});
if (scope.removeLoadJob) {
scope.removeLoadJob();
}
@@ -738,6 +705,24 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
scope.verbosity = data.verbosity;
scope.job_tags = data.job_tags;
scope.variables = ParseVariableString(data.extra_vars);
scope.users_url = (data.summary_fields.created_by) ? '/#/users/' + data.summary_fields.created_by.id : '';
scope.created_by = (data.summary_fields.created_by) ? data.summary_fields.created_by.username : '';
if (data.summary_fields.credential) {
scope.credential_name = data.summary_fields.credential.name;
scope.credential_url = data.related.credential
.replace('api/v1', '#');
} else {
scope.credential_name = "";
}
if (data.summary_fields.cloud_credential) {
scope.cloud_credential_name = data.summary_fields.cloud_credential.name;
scope.cloud_credential_url = data.related.cloud_credential
.replace('api/v1', '#');
} else {
scope.cloud_credential_name = "";
}
for (i=0; i < verbosity_options.length; i++) {
if (verbosity_options[i].value === data.verbosity) {
@@ -792,10 +777,6 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
});
//scope.setSearchAll('host');
scope.$emit('LoadPlays', data.related.job_events);
scope.$emit('GetCreatedByNames', data.related.created_by);
if (!scope.credential_name) {
scope.$emit('GetCredentialNames', data);
}
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
@@ -1415,5 +1396,5 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
JobDetailController.$inject = [ '$location', '$rootScope', '$filter', '$scope', '$compile', '$routeParams', '$log', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath',
'Wait', 'Rest', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList',
'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'EventViewer', 'DeleteJob', 'PlaybookRun', 'HostEventsViewer', 'LoadPlays', 'LoadTasks',
'LoadHosts', 'HostsEdit', 'ParseVariableString', 'GetChoices'
'LoadHosts', 'HostsEdit', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels'
];

View File

@@ -13,7 +13,7 @@
export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, ProjectList, GenerateList, LoadBreadCrumbs,
Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate,
Refresh, Wait, Stream, GetChoices, Empty, Find, LogViewer, GetProjectIcon, GetProjectToolTip) {
Refresh, Wait, Stream, GetChoices, Empty, Find, LogViewer, GetProjectIcon, GetProjectToolTip, $filter) {
ClearScope();
@@ -309,29 +309,37 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams,
});
$scope.cancelUpdate = function (id, name) {
// Start the cancel process
var i, project, found = false;
for (i = 0; i < $scope.projects.length; i++) {
if ($scope.projects[i].id === id) {
project = $scope.projects[i];
found = true;
break;
}
}
if (found && project.related.current_update) {
Rest.setUrl(project.related.current_update);
Rest.get()
.success(function (data) {
$scope.$emit('Check_Cancel', data);
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + project.related.current_update + ' failed. GET status: ' + status });
});
} else {
Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + name + '. Click the <em>Refresh</em> ' +
'button to view the latet status.', 'alert-info');
}
// // Start the cancel process
// var i, project, found = false;
// for (i = 0; i < $scope.projects.length; i++) {
// if ($scope.projects[i].id === id) {
// project = $scope.projects[i];
// found = true;
// break;
// }
// }
Rest.setUrl(GetBasePath("projects") + id);
Rest.get()
.success(function (data) {
if (data.related.current_update) {
Rest.setUrl(data.related.current_update);
Rest.get()
.success(function (data) {
$scope.$emit('Check_Cancel', data);
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + data.related.current_update + ' failed. GET status: ' + status });
});
} else {
Alert('Update Not Found', 'An SCM update does not appear to be running for project: ' + $filter('sanitize')(name) + '. Click the <em>Refresh</em> ' +
'button to view the latest status.', 'alert-info',undefined,undefined,undefined,undefined,true);
}
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Call to get project failed. GET status: ' + status });
})
};
$scope.refresh = function () {
@@ -384,7 +392,7 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $routeParams,
ProjectsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'ProjectList', 'generateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath',
'SelectionInit', 'ProjectUpdate', 'Refresh', 'Wait', 'Stream', 'GetChoices', 'Empty', 'Find',
'LogViewer', 'GetProjectIcon', 'GetProjectToolTip'
'LogViewer', 'GetProjectIcon', 'GetProjectToolTip', '$filter'
];

View File

@@ -176,7 +176,7 @@ TeamsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$r
export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm, Rest, Alert, ProcessErrors,
LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, GetBasePath, CheckAccess,
OrganizationList, Wait, Stream, permissionsChoices, permissionsLabel, permissionsSearchSelect) {
OrganizationList, Wait, Stream, fieldChoices, fieldLabels, permissionsSearchSelect) {
ClearScope();
@@ -192,16 +192,17 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
$scope.permission_search_select = [];
// return a promise from the options request with the permission type choices (including adhoc) as a param
var permissionsChoice = permissionsChoices({
var permissionsChoice = fieldChoices({
scope: $scope,
url: 'api/v1/' + base + '/' + id + '/permissions/'
url: 'api/v1/' + base + '/' + id + '/permissions/',
field: 'permission_type'
});
// manipulate the choices from the options request to be set on
// scope and be usable by the list form
permissionsChoice.then(function (choices) {
choices =
permissionsLabel({
fieldLabels({
choices: choices
});
_.map(choices, function(n, key) {
@@ -209,8 +210,6 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
});
});
$scope.team_id = id;
// manipulate the choices from the options request to be usable
// by the search option for permission_type, you can't inject the
// list until this is done!
@@ -221,8 +220,11 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
});
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
generator.reset();
$scope.$emit('loadTeam');
});
$scope.team_id = id;
$scope.PermissionAddAllowed = false;
// Retrieve each related set and any lookups
@@ -253,59 +255,65 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
}
});
// Retrieve detail record and prepopulate the form
Wait('start');
Rest.setUrl(defaultUrl + ':id/');
Rest.get({
params: {
id: id
}
})
.success(function (data) {
var fld, related, set;
$scope.team_name = data.name;
for (fld in form.fields) {
if (data[fld]) {
$scope[fld] = data[fld];
master[fld] = $scope[fld];
}
// Retrieve each related set and any lookups
if ($scope.loadTeamRemove) {
$scope.loadTeamRemove();
}
$scope.loadTeamRemove = $scope.$on('loadTeam', function () {
// Retrieve detail record and prepopulate the form
Wait('start');
Rest.setUrl(defaultUrl + ':id/');
Rest.get({
params: {
id: id
}
related = data.related;
for (set in form.related) {
if (related[set]) {
relatedSets[set] = {
url: related[set],
iterator: form.related[set].iterator
};
}
}
// Initialize related search functions. Doing it here to make sure relatedSets object is populated.
RelatedSearchInit({
scope: $scope,
form: form,
relatedSets: relatedSets
});
RelatedPaginateInit({
scope: $scope,
relatedSets: relatedSets
});
LookUpInit({
scope: $scope,
form: form,
current_item: data.organization,
list: OrganizationList,
field: 'organization',
input_type: 'radio'
});
$scope.organization_url = data.related.organization;
$scope.$emit('teamLoaded');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id +
'. GET status: ' + status });
});
.success(function (data) {
var fld, related, set;
$scope.team_name = data.name;
for (fld in form.fields) {
if (data[fld]) {
$scope[fld] = data[fld];
master[fld] = $scope[fld];
}
}
related = data.related;
for (set in form.related) {
if (related[set]) {
relatedSets[set] = {
url: related[set],
iterator: form.related[set].iterator
};
}
}
// Initialize related search functions. Doing it here to make sure relatedSets object is populated.
RelatedSearchInit({
scope: $scope,
form: form,
relatedSets: relatedSets
});
RelatedPaginateInit({
scope: $scope,
relatedSets: relatedSets
});
LookUpInit({
scope: $scope,
form: form,
current_item: data.organization,
list: OrganizationList,
field: 'organization',
input_type: 'radio'
});
$scope.organization_url = data.related.organization;
$scope.$emit('teamLoaded');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to retrieve team: ' + $routeParams.team_id +
'. GET status: ' + status });
});
});
$scope.getPermissionText = function () {
if (this.permission.permission_type !== "admin" && this.permission.run_ad_hoc_commands) {
@@ -431,5 +439,5 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
TeamsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect'
'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect'
];

View File

@@ -208,7 +208,7 @@ UsersAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$r
export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeParams, UserForm, GenerateForm, Rest, Alert,
ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, GetBasePath,
Prompt, CheckAccess, ResetForm, Wait, Stream, permissionsChoices, permissionsLabel, permissionsSearchSelect) {
Prompt, CheckAccess, ResetForm, Wait, Stream, fieldChoices, fieldLabels, permissionsSearchSelect) {
ClearScope();
@@ -224,16 +224,17 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP
$scope.permission_search_select = [];
// return a promise from the options request with the permission type choices (including adhoc) as a param
var permissionsChoice = permissionsChoices({
var permissionsChoice = fieldChoices({
scope: $scope,
url: 'api/v1/' + base + '/' + id + '/permissions/'
url: 'api/v1/' + base + '/' + id + '/permissions/',
field: 'permission_type'
});
// manipulate the choices from the options request to be set on
// scope and be usable by the list form
permissionsChoice.then(function (choices) {
choices =
permissionsLabel({
fieldLabels({
choices: choices
});
_.map(choices, function(n, key) {
@@ -241,22 +242,23 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP
});
});
// manipulate the choices from the options request to be usable
// by the search option for permission_type, you can't inject the
// list until this is done!
permissionsChoice.then(function (choices) {
form.related.permissions.fields.permission_type.searchOptions =
permissionsSearchSelect({
choices: choices
});
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
generator.reset();
$scope.$emit("loadForm");
});
if ($scope.removeFormReady) {
$scope.removeFormReady();
}
$scope.removeFormReady = $scope.$on('formReady', function () {
// manipulate the choices from the options request to be usable
// by the search option for permission_type, you can't inject the
// list until this is done!
permissionsChoice.then(function (choices) {
form.related.permissions.fields.permission_type.searchOptions =
permissionsSearchSelect({
choices: choices
});
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
generator.reset();
});
if ($scope.removePostRefresh) {
$scope.removePostRefresh();
}
@@ -470,54 +472,60 @@ export function UsersEdit($scope, $rootScope, $compile, $location, $log, $routeP
// Put form back to its original state
ResetForm();
if ($scope.removeModifyForm) {
$scope.removeModifyForm();
if ($scope.removeLoadForm) {
$scope.removeLoadForm();
}
$scope.removeModifyForm = $scope.$on('modifyForm', function () {
// Modify form based on LDAP settings
Rest.setUrl(GetBasePath('config'));
Rest.get()
.success(function (data) {
var i, fld;
if (data.user_ldap_fields) {
for (i = 0; i < data.user_ldap_fields.length; i++) {
fld = data.user_ldap_fields[i];
if (form.fields[fld]) {
form.fields[fld].readonly = true;
form.fields[fld].editRequired = false;
if (form.fields[fld].awRequiredWhen) {
delete form.fields[fld].awRequiredWhen;
$scope.removeLoadForm = $scope.$on('loadForm', function () {
if ($scope.removeModifyForm) {
$scope.removeModifyForm();
}
$scope.removeModifyForm = $scope.$on('modifyForm', function () {
// Modify form based on LDAP settings
Rest.setUrl(GetBasePath('config'));
Rest.get()
.success(function (data) {
var i, fld;
if (data.user_ldap_fields) {
for (i = 0; i < data.user_ldap_fields.length; i++) {
fld = data.user_ldap_fields[i];
if (form.fields[fld]) {
form.fields[fld].readonly = true;
form.fields[fld].editRequired = false;
if (form.fields[fld].awRequiredWhen) {
delete form.fields[fld].awRequiredWhen;
}
}
}
}
$scope.$emit('formReady');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to retrieve application config. GET status: ' + status });
});
});
Wait('start');
Rest.setUrl(defaultUrl + id + '/');
Rest.get()
.success(function (data) {
if (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') {
//this is an LDAP user
$scope.$emit('modifyForm');
} else {
$scope.$emit('formReady');
}
$scope.$emit('formReady');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to retrieve application config. GET status: ' + status });
msg: 'Failed to retrieve user: ' + id + '. GET status: ' + status });
});
});
Wait('start');
Rest.setUrl(defaultUrl + id + '/');
Rest.get()
.success(function (data) {
if (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') {
//this is an LDAP user
$scope.$emit('modifyForm');
} else {
$scope.$emit('formReady');
}
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to retrieve user: ' + id + '. GET status: ' + status });
});
}
UsersEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'UserForm', 'GenerateForm',
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope',
'GetBasePath', 'Prompt', 'CheckAccess', 'ResetForm', 'Wait', 'Stream', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect'
'GetBasePath', 'Prompt', 'CheckAccess', 'ResetForm', 'Wait', 'Stream', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect'
];

View File

@@ -118,8 +118,8 @@ export default
sourceModel: 'inventory_script',
sourceField: 'name',
ngClick: 'lookUpInventory_script()' ,
addRequired: false,
editRequired: false,
addRequired: true,
editRequired: true,
ngRequired: "source && source.value === 'custom'",
},
extra_vars: {

View File

@@ -75,7 +75,7 @@ export default
scope: scope,
// buttons: [],
width: 710,
height: 400,
height: 450,
minWidth: 300,
resizable: false,
callback: 'DialogReady',

View File

@@ -751,9 +751,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
$compile(elem)(modal_scope);
var form_scope =
generator.inject(GroupForm, { mode: 'edit', id: 'properties-tab', breadCrumbs: false, related: false, scope: properties_scope });
generator.inject(GroupForm, { mode: mode, id: 'properties-tab', breadCrumbs: false, related: false, scope: properties_scope });
var source_form_scope =
generator.inject(SourceForm, { mode: 'edit', id: 'sources-tab', breadCrumbs: false, related: false, scope: sources_scope });
generator.inject(SourceForm, { mode: mode, id: 'sources-tab', breadCrumbs: false, related: false, scope: sources_scope });
//generator.reset();
@@ -1465,6 +1465,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
// Change the lookup and regions when the source changes
sources_scope.sourceChange = function () {
sources_scope.credential_name = "";
sources_scope.credential = "";
if (sources_scope.credential_name_api_error) {
delete sources_scope.credential_name_api_error;
}
parent_scope.showSchedulesTab = (mode === 'edit' && sources_scope.source && sources_scope.source.value!=="manual") ? true : false;
SourceChange({ scope: sources_scope, form: SourceForm });
};

View File

@@ -25,9 +25,11 @@ export default
.factory('CheckLicense', ['$rootScope', '$compile', 'CreateDialog', 'Store',
'LicenseUpdateForm', 'GenerateForm', 'TextareaResize', 'ToJSON', 'GetBasePath',
'Rest', 'ProcessErrors', 'Alert', 'IsAdmin', '$location',
'Rest', 'ProcessErrors', 'Alert', 'IsAdmin', '$location', 'pendoService',
'Authorization', 'Wait',
function($rootScope, $compile, CreateDialog, Store, LicenseUpdateForm, GenerateForm,
TextareaResize, ToJSON, GetBasePath, Rest, ProcessErrors, Alert, IsAdmin, $location) {
TextareaResize, ToJSON, GetBasePath, Rest, ProcessErrors, Alert, IsAdmin, $location,
pendoService, Authorization, Wait) {
return {
getRemainingDays: function(time_remaining) {
// assumes time_remaining will be in seconds
@@ -164,21 +166,32 @@ export default
if (typeof json_data === 'object' && Object.keys(json_data).length > 0) {
Rest.setUrl(url);
Rest.post(json_data)
.success(function () {
try {
$('#license-modal-dialog').dialog('close');
}
catch(e) {
// ignore
}
.success(function (response) {
response.license_info = response;
Alert('License Accepted', 'The Ansible Tower license was updated. To review or update the license, choose View License from the Setup menu.','alert-info');
$rootScope.features = undefined;
$location.path('/home');
Authorization.getLicense()
.success(function (data) {
Authorization.setLicense(data);
pendoService.issuePendoIdentity();
Wait("stop");
$location.path('/home');
})
.error(function () {
Wait('stop');
Alert('Error', 'Failed to access license information. GET returned status: ' + status, 'alert-danger',
$location.path('/logout'));
});
})
.error(function (data, status) {
.catch(function (response) {
scope.license_json_api_error = "A valid license key in JSON format is required";
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to update license. POST returned: ' + status
ProcessErrors(scope, response.data, response.status, null, { hdr: 'Error!',
msg: 'Failed to update license. POST returned: ' + response.status
});
});
} else {

View File

@@ -39,16 +39,25 @@ angular.module('LoadConfigHelper', ['Utilities'])
if(angular.isObject(response.data)){
$AnsibleConfig = _.extend($AnsibleConfig, response.data);
Store('AnsibleConfig', $AnsibleConfig);
if ($rootScope.loginConfig) {
$rootScope.loginConfig.resolve('config loaded');
}
$rootScope.$emit('ConfigReady');
}
else {
$log.info('local_settings.json is not a valid object');
if ($rootScope.loginConfig) {
$rootScope.loginConfig.resolve('config loaded');
}
$rootScope.$emit('ConfigReady');
}
}, function() {
//local_settings.json not found
$log.info('local_settings.json not found');
if ($rootScope.loginConfig) {
$rootScope.loginConfig.resolve('config loaded');
}
$rootScope.$emit('ConfigReady');
});
});
@@ -57,15 +66,16 @@ angular.module('LoadConfigHelper', ['Utilities'])
// load config.js
$log.info('attempting to load config.js');
$http({ method:'GET', url: $basePath + 'config.js' })
.success(function(data) {
.then(function(response) {
$log.info('loaded config.js');
$AnsibleConfig = eval(data);
$AnsibleConfig = eval(response.data);
Store('AnsibleConfig', $AnsibleConfig);
$rootScope.$emit('LoadConfig');
})
.error(function(data, status) {
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
msg: 'Failed to load ' + $basePath + '/config.js. GET status: ' + status
.catch(function(response) {
response.data = 'Failed to load ' + $basePath + '/config.js';
ProcessErrors($rootScope, response, response.status, null, { hdr: 'Error!',
msg: 'Failed to load ' + $basePath + '/config.js.'
});
});
};

View File

@@ -60,7 +60,8 @@ export default
logout: function () {
// the following puts our primary scope up for garbage collection, which
// should prevent content flash from the prior user.
var scope = angular.element(document.getElementById('main-view')).scope();
var x, scope = angular.element(document.getElementById('main-view')).scope();
scope.$destroy();
//$rootScope.$destroy();
@@ -78,6 +79,9 @@ export default
$cookieStore.remove('lastPath');
$rootScope.lastPath = '/home';
}
x = Store('sessionTime');
x[$rootScope.current_user.id].loggedIn = false;
Store('sessionTime', x);
$rootScope.lastUser = $cookieStore.get('current_user').id;
$cookieStore.remove('token_expires');
@@ -94,7 +98,7 @@ export default
$rootScope.token_expires = null;
$rootScope.login_username = null;
$rootScope.login_password = null;
$rootScope.sessionTimer.expireSession();
$rootScope.sessionTimer.clearTimers();
},
getLicense: function () {
@@ -112,6 +116,7 @@ export default
var license = data.license_info;
license.analytics_status = data.analytics_status;
license.version = data.version;
license.ansible_version = data.ansible_version;
license.tested = false;
Store('license', license);
$rootScope.features = Store('license').features;
@@ -149,7 +154,6 @@ export default
// store the response values in $rootScope so we can get to them later
$rootScope.current_user = response.results[0];
$cookieStore.put('current_user', response.results[0]); //keep in session cookie in the event of browser refresh
$rootScope.$emit('OpenSocket');
},
restoreUserInfo: function () {

View File

@@ -12,7 +12,8 @@ export default
Store, $log) {
return {
setPendoOptions: function (config) {
var options = {
var tower_version = config.version.split('-')[0],
options = {
visitor: {
id: null,
role: null,
@@ -23,7 +24,9 @@ export default
planLevel: config.license_type,
planPrice: config.instance_count,
creationDate: config.license_date,
trial: config.trial
trial: config.trial,
tower_version: tower_version,
ansible_version: config.ansible_version
}
};
if(config.analytics_status === 'detailed'){

View File

@@ -23,22 +23,21 @@
*/
export default
['$rootScope', '$cookieStore', 'transitionTo', 'CreateDialog', 'Authorization',
'Store', '$interval',
'Store', '$interval', '$location', '$q',
function ($rootScope, $cookieStore, transitionTo, CreateDialog, Authorization,
Store, $interval) {
Store, $interval, $location, $q) {
return {
sessionTime: null,
timeout: null,
getSessionTime: function () {
if(Store('sessionTime_'+$rootScope.current_user.id)){
return Store('sessionTime_'+$rootScope.current_user.id);
if(Store('sessionTime')){
return Store('sessionTime')[$rootScope.current_user.id].time;
}
else {
return 0;
return 0;
}
},
isExpired: function (increase) {
@@ -83,14 +82,24 @@ export default
this.sessionTime = 0;
this.clearTimers();
$cookieStore.put('sessionExpired', true);
transitionTo('signOut');
},
moveForward: function () {
var tm, t;
var tm, t, x, y;
tm = ($AnsibleConfig.session_timeout) ? $AnsibleConfig.session_timeout : 1800;
t = new Date().getTime() + (tm * 1000);
Store('sessionTime_'+$rootScope.current_user.id, t);
x = {
time: t,
loggedIn: true
};
if(Store('sessionTime')){
y = Store('sessionTime');
}
else {
y = {};
}
y[$rootScope.current_user.id] = x;
Store('sessionTime' , y);
$rootScope.sessionExpired = false;
$cookieStore.put('sessionExpired', false);
this.startTimers();
@@ -148,6 +157,14 @@ export default
$('#idle-modal').dialog('close');
}
that.expireSession('idle');
$location.url('/login');
}
if(Store('sessionTime') &&
Store('sessionTime')[$rootScope.current_user.id] &&
Store('sessionTime')[$rootScope.current_user.id].loggedIn === false){
that.expireSession();
$location.url('/login');
}
}, 1000);
@@ -156,11 +173,15 @@ export default
clearTimers: function(){
$interval.cancel($rootScope.expireTimer);
delete $rootScope.expireTimer;
},
init: function () {
var deferred = $q.defer();
this.moveForward();
return this;
deferred.resolve(this);
return deferred.promise;
}
};
}

View File

@@ -110,17 +110,11 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l
setLoginFocus();
});
if ($AnsibleConfig.custom_logo) {
scope.customLogo = "custom_console_logo.png"
scope.customLogoPresent = true;
} else {
scope.customLogo = "login_modal_logo.png";
scope.customLogoPresent = false;
}
scope.customLoginInfo = $AnsibleConfig.custom_login_info;
scope.customLoginInfoPresent = (scope.customLoginInfo) ? true : false;
$rootScope.loginConfig.promise.then(function () {
scope.customLogo = ($AnsibleConfig.custom_logo) ? "custom_console_logo.png" : "tower_console_logo.png";
scope.customLoginInfo = $AnsibleConfig.custom_login_info;
scope.customLoginInfoPresent = ($AnsibleConfig.customLoginInfo) ? true : false;
});
// Reset the login form
//scope.loginForm.login_username.$setPristine();
@@ -171,9 +165,12 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l
Authorization.getUser()
.success(function (data) {
Authorization.setUserInfo(data);
$rootScope.sessionTimer = Timer.init();
$rootScope.user_is_superuser = data.results[0].is_superuser;
scope.$emit('AuthorizationGetLicense');
Timer.init().then(function(timer){
$rootScope.sessionTimer = timer;
$rootScope.$emit('OpenSocket');
$rootScope.user_is_superuser = data.results[0].is_superuser;
scope.$emit('AuthorizationGetLicense');
});
})
.error(function (data, status) {
Authorization.logout();
@@ -200,7 +197,7 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l
function (data) {
var key;
Wait('stop');
if (data.data.non_field_errors && data.data.non_field_errors.length === 0) {
if (data && data.data && data.data.non_field_errors && data.data.non_field_errors.length === 0) {
// show field specific errors returned by the API
for (key in data.data) {
scope[key + 'Error'] = data.data[key][0];

View File

@@ -25,7 +25,7 @@
var options = [],
error = "";
function parseGoogle(option, key) {
function parseGoogle(option) {
var newOption = {};
newOption.type = "google";

View File

@@ -1,14 +0,0 @@
<div class="row">
<div class="left-side col-sm-4 col-xs-12">
<img id="about-modal-logo" src="static/assets/tower_console_bug.png">
</div>
<div class="right-side col-sm-8 col-xs-12">
<img id="about-modal-titlelogo" src="static/assets/tower_login_logo.png"><br>
<p>Tower Version <span id='about-modal-version'></span></p>
<textarea class="form-control" rows="2" readonly>Copyright 2015. All rights reserved.&#10Ansible and Ansible Tower are registered trademarks of Ansible, Inc.&#10</textarea>
<br>
<p>Visit <a href="http://www.ansible.com" target="_blank">Ansible.com</a> for more information!</p>
</div>
</div>

View File

@@ -33,8 +33,24 @@
<div class="form-horizontal" role="form" id="job-status-form">
<div class="form-group" ng-show="job_status.explanation">
<label class="col-lg-2 col-md-12 col-sm-12 col-xs-12">Explanation</label>
<div class="col-lg-10 col-md-12 col-sm-12 col-xs-12 job_status_explanation" ng-bind-html="job_status.explanation"></div>
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-3 col-xs-12">Explanation</label>
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation"
ng-show="!previousTaskFailed" ng-bind-html="job_status.explanation"></div>
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9 job_status_explanation"
ng-show="previousTaskFailed">Previous Task Failed
<a
href=""
id="explanation_help"
aw-pop-over="{{ task_detail }}"
aw-pop-over-watch="task_detail"
data-placement="bottom"
data-container="body" class="help-link" over-title="Failure Detail"
title=""
tabindex="-1">
<i class="fa fa-question-circle">
</i>
</a>
</div>
</div>
<div class="form-group" ng-show="job_status.traceback">

View File

@@ -10,8 +10,8 @@
* @description This controller for permissions add
*/
export default
['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'permissionsChoices', 'permissionsLabel',
function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, permissionsChoices, permissionsLabel) {
['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath', 'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'fieldChoices', 'fieldLabels',
function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, fieldChoices, fieldLabels) {
ClearScope();
@@ -22,13 +22,14 @@ export default
base = $location.path().replace(/^\//, '').split('/')[0],
master = {};
var permissionsChoice = permissionsChoices({
var permissionsChoice = fieldChoices({
scope: $scope,
url: 'api/v1/' + base + '/' + id + '/permissions/'
url: 'api/v1/' + base + '/' + id + '/permissions/',
field: 'permission_type'
});
permissionsChoice.then(function (choices) {
return permissionsLabel({
return fieldLabels({
choices: choices
});
}).then(function (choices) {

View File

@@ -10,8 +10,8 @@
* @description This controller for permissions edit
*/
export default
['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'permissionsChoices', 'permissionsLabel',
function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, permissionsChoices, permissionsLabel) {
['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'permissionsForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait', 'permissionsCategoryChange', 'fieldChoices', 'fieldLabels',
function($scope, $rootScope, $compile, $location, $log, $routeParams, permissionsForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess, Wait, permissionsCategoryChange, fieldChoices, fieldLabels) {
ClearScope();
@@ -25,13 +25,14 @@ export default
$scope.permission_label = {};
var permissionsChoice = permissionsChoices({
var permissionsChoice = fieldChoices({
scope: $scope,
url: 'api/v1/' + base + '/' + base_id + '/permissions/'
url: 'api/v1/' + base + '/' + base_id + '/permissions/',
field: 'permission_type'
});
permissionsChoice.then(function (choices) {
return permissionsLabel({
return fieldLabels({
choices: choices
});
}).then(function (choices) {

View File

@@ -12,8 +12,8 @@
export default
['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'permissionsList', 'generateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess', 'Wait', 'permissionsChoices', 'permissionsLabel', 'permissionsSearchSelect',
function ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, permissionsList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, CheckAccess, Wait, permissionsChoices, permissionsLabel, permissionsSearchSelect) {
['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'permissionsList', 'generateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess', 'Wait', 'fieldChoices', 'fieldLabels', 'permissionsSearchSelect',
function ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, permissionsList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, CheckAccess, Wait, fieldChoices, fieldLabels, permissionsSearchSelect) {
ClearScope();
@@ -27,16 +27,17 @@ export default
$scope.permission_search_select = [];
// return a promise from the options request with the permission type choices (including adhoc) as a param
var permissionsChoice = permissionsChoices({
var permissionsChoice = fieldChoices({
scope: $scope,
url: 'api/v1/' + base + '/' + base_id + '/permissions/'
url: 'api/v1/' + base + '/' + base_id + '/permissions/',
field: 'permission_type'
});
// manipulate the choices from the options request to be set on
// scope and be usable by the list form
permissionsChoice.then(function (choices) {
choices =
permissionsLabel({
fieldLabels({
choices: choices
});
_.map(choices, function(n, key) {

View File

@@ -12,8 +12,6 @@ import list from './shared/permissions.list';
import form from './shared/permissions.form';
import permissionsCategoryChange from './shared/category-change.factory';
import permissionsChoices from './shared/get-choices.factory';
import permissionsLabel from './shared/get-labels.factory';
import permissionsSearchSelect from './shared/get-search-select.factory';
export default
@@ -25,6 +23,4 @@ export default
.factory('permissionsList', list)
.factory('permissionsForm', form)
.factory('permissionsCategoryChange', permissionsCategoryChange)
.factory('permissionsChoices', permissionsChoices)
.factory('permissionsLabel', permissionsLabel)
.factory('permissionsSearchSelect', permissionsSearchSelect);

View File

@@ -16,24 +16,28 @@
['Rest', 'ProcessErrors', function(Rest, ProcessErrors) {
return function (params) {
var scope = params.scope,
url = params.url;
url = params.url,
field = params.field;
// Auto populate the field if there is only one result
Rest.setUrl(url);
return Rest.options()
.then(function (data) {
data = data.data;
var choices = data.actions.GET.permission_type.choices;
var choices = data.actions.GET[field].choices;
// manually add the adhoc label to the choices object
choices.push(["adhoc",
data.actions.GET.run_ad_hoc_commands.help_text]);
// manually add the adhoc label to the choices object if
// the permission_type field
if (field === "permission_type") {
choices.push(["adhoc",
data.actions.GET.run_ad_hoc_commands.help_text]);
}
return choices;
})
.catch(function (data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to get permission type labels. Options requrest returned status: ' + status });
msg: 'Failed to get ' + field + ' labels. Options requrest returned status: ' + status });
});
};
}];

View File

@@ -11,8 +11,8 @@
*************************************************/
export default
[ '$rootScope', '$q',
function ($rootScope, $q) {
[ '$rootScope', '$q', '$injector',
function ($rootScope, $q, $injector) {
return {
response: function(config) {
if(config.headers('auth-token-timeout') !== null){
@@ -21,8 +21,10 @@
return config;
},
responseError: function(rejection){
if( rejection.data && !_.isEmpty(rejection.data.detail) && rejection.data.detail === "Maximum per-user sessions reached"){
if(rejection && rejection.data && rejection.data.detail && rejection.data.detail === "Maximum per-user sessions reached"){
$rootScope.sessionTimer.expireSession('session_limit');
var location = $injector.get('$location');
location.url('/login');
return $q.reject(rejection);
}
return $q.reject(rejection);

View File

@@ -6,6 +6,8 @@
import restServicesFactory from './restServices.factory';
import interceptors from './interceptors.service';
import fieldChoices from './get-choices.factory';
import fieldLabels from './get-labels.factory';
export default
angular.module('RestServices', [])
@@ -13,4 +15,6 @@ export default
$httpProvider.interceptors.push('RestInterceptor');
}])
.factory('Rest', restServicesFactory)
.service('RestInterceptor', interceptors);
.service('RestInterceptor', interceptors)
.factory('fieldChoices', fieldChoices)
.factory('fieldLabels', fieldLabels);

View File

@@ -53,8 +53,8 @@
</p>
</div>
</a>
<a link-to="managementJobsList" class="SetupItem SetupItem--aside HoverIcon Media">
<i class="HoverIcon-icon HoverIcon-icon--opacity HoverIcon-icon--color Media-figure SetupItem-icon SetupItem-icon--aside" ng-if="user_is_superuser">
<a link-to="managementJobsList" class="SetupItem SetupItem--aside HoverIcon Media" ng-if="user_is_superuser">
<i class="HoverIcon-icon HoverIcon-icon--opacity HoverIcon-icon--color Media-figure SetupItem-icon SetupItem-icon--aside">
<aw-icon name="ManagementJobs"></aw-icon>
</i>
<div class="Media-block">

View File

@@ -252,15 +252,20 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
if ((!fieldErrors) && defaultMsg) {
Alert(defaultMsg.hdr, defaultMsg.msg);
}
} else if (typeof data === 'object' && Object.keys(data).length > 0) {
keys = Object.keys(data);
if (Array.isArray(data[keys[0]])) {
msg = data[keys[0]][0];
} else if (typeof data === 'object' && data !== null){
if(Object.keys(data).length > 0) {
keys = Object.keys(data);
if (Array.isArray(data[keys[0]])) {
msg = data[keys[0]][0];
}
else {
msg = data[keys[0]];
}
Alert(defaultMsg.hdr, msg);
}
else {
msg = data[keys[0]];
Alert(defaultMsg.hdr, defaultMsg.msg);
}
Alert(defaultMsg.hdr, msg);
} else {
Alert(defaultMsg.hdr, defaultMsg.msg);
}

View File

@@ -275,7 +275,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper'])
if (/^\-?\d*$/.test(viewValue)) {
// it is valid
ctrl.$setValidity('integer', true);
if ( viewValue === '-' || viewValue === '-0' || viewValue === '' || viewValue === null) {
if ( viewValue === '-' || viewValue === '-0' || viewValue === null) {
ctrl.$setValidity('integer', false);
return viewValue;
}

View File

@@ -221,15 +221,68 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
if (obj2_obj && obj2_obj.name && !/^_delete/.test(obj2_obj.name)) {
obj2_obj.base = obj2;
obj2_obj.name = $filter('sanitize')(obj2_obj.name);
descr += obj2 + " <a href=\"" + BuildUrl(obj2_obj) + "\">" + obj2_obj.name + '</a>' + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
descr_nolink += obj2 + ' ' + obj2_obj.name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
descr += obj2 +
" <a href=\"" + BuildUrl(obj2_obj) + "\">" +
obj2_obj.name + '</a>';
if (activity.object_association === 'admins') {
if (activity.operation === 'disassociate') {
descr += ' from being an admin of ';
} else {
descr += ' as an admin of ';
}
} else {
if (activity.operation === 'disassociate') {
descr += ' from ';
} else {
descr += ' to ';
}
}
descr_nolink += obj2 + ' ' + obj2_obj.name;
if (activity.object_association === 'admins') {
if (activity.operation === 'disassociate') {
descr_nolink += ' from being an admin of ';
} else {
descr_nolink += ' as an admin of ';
}
} else {
if (activity.operation === 'disassociate') {
descr_nolink += ' from ';
} else {
descr_nolink += ' to ';
}
}
} else if (obj2) {
name = '';
if (obj2_obj && obj2_obj.name) {
name = ' ' + stripDeleted(obj2_obj.name);
}
descr += obj2 + name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
descr_nolink += obj2 + name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
if (activity.object_association === 'admins') {
if (activity.operation === 'disassociate') {
descr += ' from being an admin of ';
} else {
descr += ' as an admin of ';
}
} else {
if (activity.operation === 'disassociate') {
descr += ' from ';
} else {
descr += ' to ';
}
}
descr_nolink += obj2 + ' ' + obj2_obj.name;
if (activity.object_association === 'admins') {
if (activity.operation === 'disassociate') {
descr_nolink += ' from being an admin of ';
} else {
descr_nolink += ' as an admin of ';
}
} else {
if (activity.operation === 'disassociate') {
descr_nolink += ' from ';
} else {
descr_nolink += ' to ';
}
}
}
if (obj1_obj && obj1_obj.name && !/^\_delete/.test(obj1_obj.name)) {
obj1_obj.base = obj1;