diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index 5dc5d3f5f7..ae05097723 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -12,7 +12,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, CredentialList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, - ClearScope, ProcessErrors, GetBasePath, SelectionInit) + ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -33,20 +33,45 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res scope.removePostRefresh(); } scope.removePostRefresh = scope.$on('PostRefresh', function() { - // After a refresh, populate the organization name on each row + list.fields.kind.searchOptions = scope.credential_kind_options; + + // Translate the kind value for(var i=0; i < scope.credentials.length; i++) { + /* if (scope.credentials[i].summary_fields.user) { scope.credentials[i].user_username = scope.credentials[i].summary_fields.user.username; } if (scope.credentials[i].summary_fields.team) { scope.credentials[i].team_name = scope.credentials[i].summary_fields.team.name; } + */ + for (var j=0; j < scope.credential_kind_options.length; j++) { + if (scope.credential_kind_options[j].value == scope.credentials[i].kind) { + scope.credentials[i].kind = scope.credential_kind_options[j].label + break; + } + } } }); - SearchInit({ scope: scope, set: 'credentials', list: list, url: defaultUrl }); - PaginateInit({ scope: scope, list: list, url: defaultUrl }); - scope.search(list.iterator); + if (scope.removeChoicesReady) { + scope.removeChoicesReady(); + } + scope.removeChoicesReady = scope.$on('choicesReady', function() { + SearchInit({ scope: scope, set: 'credentials', list: list, url: defaultUrl }); + PaginateInit({ scope: scope, list: list, url: defaultUrl }); + scope.search(list.iterator); + }); + + // Load the list of options for Kind + GetChoices({ + scope: scope, + url: defaultUrl, + field: 'kind', + variable: 'credential_kind_options', + callback: 'choicesReady' + }); + LoadBreadCrumbs(); @@ -84,7 +109,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res CredentialsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'CredentialList', 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', - 'GetBasePath', 'SelectionInit']; + 'GetBasePath', 'SelectionInit', 'GetChoices']; function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, @@ -171,23 +196,39 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa var data = {} for (var fld in form.fields) { - if (scope[fld] === null) { - data[fld] = ""; - } - else { - data[fld] = scope[fld]; + if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' && + fld !== 'ssh_password') { + if (scope[fld] === null) { + data[fld] = ""; + } + else { + data[fld] = scope[fld]; + } } } if (!Empty(scope.team)) { data.team = scope.team; + data.user = ""; } else { data.user = scope.user; + data.team = ""; } data['kind'] = scope['kind'].value; + switch (data['kind']) { + case 'ssh': + data['username'] = scope['ssh_username']; + data['password'] = scope['ssh_password']; + break; + case 'aws': + data['username'] = scope['access_key']; + data['password'] = scope['secret_key']; + break; + } + if (Empty(data.team) && Empty(data.user)) { Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' + 'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger'); @@ -353,6 +394,29 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP scope['owner'] = 'team'; } master['owner'] = scope['owner']; + + for (var i=0; i < scope.credential_kind_options.length; i++) { + if (scope.credential_kind_options[i].value == data.kind) { + scope.kind = scope.credential_kind_options[i]; + break; + } + } + master['kind'] = scope['kind']; + + switch (data.kind) { + case 'aws': + scope['access_key'] = data.username; + scope['secret_key'] = data.password; + master['access_key'] = scope['access_key']; + master['secret_key'] = scope['secret_key']; + break; + case 'ssh': + scope['ssh_username'] = data.username; + scope['ssh_password'] = data.password; + master['ssh_username'] = scope['ssh_username']; + master['ssh_password'] = scope['ssh_password']; + break; + } scope.$emit('credentialLoaded'); }) @@ -373,26 +437,43 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP // Save changes to the parent scope.formSave = function() { generator.clearApiErrors(); - + var data = {} for (var fld in form.fields) { - if (scope[fld] === null) { - data[fld] = ""; - } - else { - data[fld] = scope[fld]; + if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' && + fld !== 'ssh_password') { + if (scope[fld] === null) { + data[fld] = ""; + } + else { + data[fld] = scope[fld]; + } } } + if (!Empty(scope.team)) { data.team = scope.team; + data.user = ""; } else { data.user = scope.user; + data.team = ""; } data['kind'] = scope['kind'].value; + switch (data['kind']) { + case 'ssh': + data['username'] = scope['ssh_username']; + data['password'] = scope['ssh_password']; + break; + case 'aws': + data['username'] = scope['access_key']; + data['password'] = scope['secret_key']; + break; + } + if (Empty(data.team) && Empty(data.user)) { Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' + 'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger'); diff --git a/awx/ui/static/js/controllers/JobTemplates.js b/awx/ui/static/js/controllers/JobTemplates.js index 98d8392202..4d0bbb54a7 100644 --- a/awx/ui/static/js/controllers/JobTemplates.js +++ b/awx/ui/static/js/controllers/JobTemplates.js @@ -82,7 +82,8 @@ JobTemplatesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$rout function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, - GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange) + GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit, + md5Setup, ParseTypeChange) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -123,23 +124,30 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP field: 'inventory' }); - LookUpInit({ - url: GetBasePath('credentials') + '?cloud=false', - scope: scope, - form: form, - current_item: null, - list: CredentialList, - field: 'credential' - }); - + // Clone the CredentialList object for use with cloud_credential. Cloning + // and changing properties to avoid collision. + var CloudCredentialList = {}; + jQuery.extend(true, CloudCredentialList, CredentialList); + CloudCredentialList.name = 'cloudcredentials', + CloudCredentialList.iterator = 'cloudcredential', + LookUpInit({ url: GetBasePath('credentials') + '?cloud=true', scope: scope, form: form, current_item: null, - list: CredentialList, + list: CloudCredentialList, field: 'cloud_credential' }); + + LookUpInit({ + url: GetBasePath('credentials') + '?kind=ssh', + scope: scope, + form: form, + current_item: null, + list: CredentialList, + field: 'credential' + }); // Update playbook select whenever project value changes var selectPlaybook = function(oldValue, newValue) { @@ -277,7 +285,8 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP JobTemplatesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', - 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'md5Setup', 'ParseTypeChange' ]; + 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', + 'md5Setup', 'ParseTypeChange' ]; function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index 42b93da95c..391234cf6b 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -75,15 +75,15 @@ angular.module('CredentialFormDefinition', []) label: 'Access Key', type: 'text', ngShow: "kind.value == 'aws'", - awRequiredWhen: { variable: "aws_required", init: "false" }, + awRequiredWhen: { variable: "aws_required", init: false }, autocomplete: false, apiField: 'username' }, secret_key: { - label: 'Secrent Key', + label: 'Secret Key', type: 'password', ngShow: "kind.value == 'aws'", - awRequiredWhen: { variable: "aws_required", init: "false" }, + awRequiredWhen: { variable: "aws_required", init: false }, autocomplete: false, ask: false, clear: false, @@ -97,9 +97,9 @@ angular.module('CredentialFormDefinition', []) autocomplete: false }, "password": { - labelBind: 'passwordLabel', + label: 'Password', type: 'password', - ngShow: "kind.value && kind.value !== 'aws'", + ngShow: "kind.value == 'rax' || kind.value == 'scm'", awRequiredWhen: {variable: 'rackspace_required', init: false }, ngChange: "clearPWConfirm('password_confirm')", ask: false, @@ -108,15 +108,37 @@ angular.module('CredentialFormDefinition', []) autocomplete: false }, "password_confirm": { - labelBind: 'passwordConfirmLabel', + label: 'Confirm Password', type: 'password', - ngShow: "kind.value && kind.value !== 'aws'", + ngShow: "kind.value == 'rax' || kind.value == 'scm'", addRequired: false, editRequired: false, awPassMatch: true, associated: 'password', autocomplete: false }, + "ssh_password": { + label: 'SSH Password', + type: 'password', + ngShow: "kind.value == 'ssh'", + ngChange: "clearPWConfirm('password_confirm')", + addRequired: false, + editRequired: false, + ask: true, + clear: true, + associated: 'ssh_password_confirm', + autocomplete: false + }, + "ssh_password_confirm": { + label: 'Confirm SSH Password', + type: 'password', + ngShow: "kind.value == 'ssh'", + addRequired: false, + editRequired: false, + awPassMatch: true, + associated: 'ssh_password', + autocomplete: false + }, "ssh_key_data": { labelBind: 'sshKeyDataLabel', type: 'textarea', diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index a7bc3eaeb6..329ebb969e 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -87,7 +87,7 @@ angular.module('JobTemplateFormDefinition', []) type: 'lookup', sourceModel: 'cloud_credential', sourceField: 'name', - ngClick: 'lookUpCredential()', + ngClick: 'lookUpCloudcredential()', addRequired: false, editRequired: false, column: 1 diff --git a/awx/ui/static/js/helpers/Credentials.js b/awx/ui/static/js/helpers/Credentials.js index 2d3fd0708f..a1ffc003d3 100644 --- a/awx/ui/static/js/helpers/Credentials.js +++ b/awx/ui/static/js/helpers/Credentials.js @@ -18,27 +18,20 @@ angular.module('CredentialsHelper', ['Utilities']) // Put things in a default state scope['usernameLabel'] = 'Username'; - scope['passwordLabel'] = 'Password'; - scope['passwordConfirmLabel'] = 'Confirm Password'; scope['aws_required'] = false; scope['rackspace_required'] = false; scope['sshKeyDataLabel'] = 'SSH Private Key'; - form.fields['password'].clear = true; - form.fields['password'].ask = true; - + // Apply kind specific settings switch(scope['kind'].value) { case 'aws': scope['aws_required'] = true; break; case 'rax': - scope['rackspace_required'] = true; - form.fields['password'].ask = false; + scope['rackspace_required'] = true; break; - case 'ssh': + case 'ssh': scope['usernameLabel'] = 'SSH Username'; - scope['passwordLabel'] = 'SSH Password'; - scope['passwordConfirmLabel'] = 'Confirm SSH Password'; break; case 'scm': scope['sshKeyDataLabel'] = 'SCM Private Key'; diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 4fcc8e3fc0..94ef5d9926 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -8,8 +8,8 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper', 'GroupFormDefinition', 'GroupsHelper' ]) .factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', 'GroupForm', 'ProjectsForm', '$compile', 'Rest', '$location', 'ProcessErrors', - 'GetBasePath', 'Alert', - function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert) { + 'GetBasePath', 'Alert', 'Empty', + function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty) { return function(params) { var scope = params.scope; @@ -73,7 +73,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential value_supplied = true; } }); - if (passwords.length == 0 || value_supplied) { + if (Empty(passwords) || passwords.length == 0 || value_supplied) { Rest.setUrl(start_url); Rest.post(pswd) .success( function(data, status, headers, config) { @@ -97,7 +97,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential } } - if (passwords.length > 0) { + if (passwords && passwords.length > 0) { // Prompt for passwords html += "