diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index bb5beacb89..3031afdc42 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -90,7 +90,7 @@ CredentialsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$route function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GenerateList, SearchInit, PaginateInit, LookUpInit, UserList, TeamList, GetBasePath, - GetChoices, Empty, KindChange) + GetChoices, Empty, KindChange, OwnerChange) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -131,8 +131,9 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa if (!Empty($routeParams.user_id)) { // Get the username based on incoming route - var url = GetBasePath('users') + $routeParams.user_id + '/'; + scope['owner'] == 'user'; scope['user'] = $routeParams.user_id; + var url = GetBasePath('users') + $routeParams.user_id + '/'; Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { @@ -143,11 +144,11 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa { hdr: 'Error!', msg: 'Failed to retrieve user. GET status: ' + status }); }); } - - if (!Empty($routeParams.team_id)) { + else if (!Empty($routeParams.team_id)) { // Get the username based on incoming route - var url = GetBasePath('teams') + $routeParams.team_id + '/'; + scope['owner'] == 'team'; scope['team'] = $routeParams.team_id; + var url = GetBasePath('teams') + $routeParams.team_id + '/'; Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { @@ -158,6 +159,9 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa { hdr: 'Error!', msg: 'Failed to retrieve team. GET status: ' + status }); }); } + else { + scope['owner'] = 'team'; + } // Handle Kind change scope.kindChange = function () { @@ -187,7 +191,7 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa data['kind'] = scope['kind'].value; - if (!Empty(data.team) && empty(data.user)) { + 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'); } @@ -205,7 +209,12 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa { hdr: 'Error!', msg: 'Failed to create new Credential. POST status: ' + status }); }); } - }; + } + + // Handle Owner change + scope.ownerChange = function() { + OwnerChange({ scope: scope }); + } // Reset defaults scope.formReset = function() { @@ -246,13 +255,13 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa CredentialsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'UserList', 'TeamList', 'GetBasePath', 'GetChoices', 'Empty', - 'KindChange' ]; + 'KindChange', 'OwnerChange']; function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, Prompt, GetBasePath, GetChoices, - KindChange, UserList, TeamList, LookUpInit, Empty + KindChange, UserList, TeamList, LookUpInit, Empty, OwnerChange ) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior @@ -338,6 +347,15 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; } } + + if (!Empty(scope['user'])) { + scope['owner'] = 'user'; + } + else { + scope['owner'] = 'team'; + } + master['owner'] = scope['owner']; + scope.$emit('credentialLoaded'); }) .error( function(data, status, headers, config) { @@ -377,7 +395,7 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP data['kind'] = scope['kind'].value; - if (!Empty(data.team) && empty(data.user)) { + 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'); } @@ -386,7 +404,8 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP Rest.setUrl(defaultUrl + id + '/'); Rest.put(data) .success( function(data, status, headers, config) { - scope.$emit('moveUser', data); + var base = $location.path().replace(/^\//,'').split('/')[0]; + (base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1); }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, form, @@ -395,34 +414,11 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP } } - // When we're finally done updating the API, navigate out of here - function finished() { - var base = $location.path().replace(/^\//,'').split('/')[0]; - (base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1); + // Handle Owner change + scope.ownerChange = function() { + OwnerChange({ scope: scope }); } - // Did we change users? - if (scope.removeMoveUser) { - scope.removeMoveUser(); - } - scope.removeMoveUser = scope.$on('moveUser', function(e, data) { - if (master.user !== scope.user && !Empty(scope.user)) { - var url = GetBasePath('users') + scope.user + '/'; - Rest.setUrl(url); - Rest.post(data) - .success( function(data, status, headers, config) { - finished(); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST status: ' + status }); - }); - } - else { - finished(); - } - }); - // Handle Kind change scope.kindChange = function () { KindChange({ scope: scope, form: form, reset: true }); @@ -510,5 +506,5 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP CredentialsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'GetChoices', - 'KindChange', 'UserList', 'TeamList', 'LookUpInit', 'Empty']; + 'KindChange', 'UserList', 'TeamList', 'LookUpInit', 'Empty', 'OwnerChange' ]; diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index bd4c34bca4..b4686edeef 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -28,18 +28,28 @@ angular.module('CredentialFormDefinition', []) addRequired: false, editRequired: false }, + owner: { + label: 'Owned By?', + type: 'radio', + ngChange: "ownerChange()", + options: [ + { label: 'User', value: 'user' }, + { label: 'Team', value: 'team' } + ], + awPopOver: "
A credential must be associated with either a user or a team. Choosing a user allows only the selected user access " + + "to the credential. Choosing a team shares the credential with all team members.
", + dataTitle: 'Owner', + dataPlacement: 'right', + dataContainer: "body", + }, user: { label: 'User', type: 'lookup', sourceModel: 'user', sourceField: 'username', ngClick: 'lookUpUser()', - ngShow: "team == '' || team == null", - awPopOver: "A credential must be associated with either a user or a team. Choosing a user allows only the selected user access " + - "to the credential.
", - dataTitle: 'User', - dataPlacement: 'right', - dataContainer: "body" + ngShow: "owner == 'user'", + awRequiredWhen: { variable: "user_required", init: "false" } }, team: { label: 'Team', @@ -47,12 +57,8 @@ angular.module('CredentialFormDefinition', []) sourceModel: 'team', sourceField: 'name', ngClick: 'lookUpTeam()', - ngShow: "user == '' || user == null", - awPopOver: "A credential must be associated with either a user or a team. Choose a team to share a credential with " + - "all users in the team.
", - dataTitle: 'Team', - dataPlacement: 'right', - dataContainer: "body" + ngShow: "owner == 'team'", + awRequiredWhen: { variable: "team_required", init: "false" } }, kind: { label: 'Type', @@ -67,7 +73,7 @@ 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' }, @@ -75,7 +81,7 @@ angular.module('CredentialFormDefinition', []) label: 'Secrent 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, diff --git a/awx/ui/static/js/forms/Groups.js b/awx/ui/static/js/forms/Groups.js index c1ba2796c5..0ba90d67bd 100644 --- a/awx/ui/static/js/forms/Groups.js +++ b/awx/ui/static/js/forms/Groups.js @@ -112,46 +112,16 @@ angular.module('GroupFormDefinition', []) type: 'text', awRequiredWhen: {variable: "sourcePathRequired", init: "false" } }, - credential: { // FIXME: Lookup doesn't work yet! + credential: { label: 'Cloud Credential', type: 'lookup', + ngShow: "source.value !== ''", sourceModel: 'credential', sourceField: 'name', ngClick: 'lookUpCredential()', addRequired: false, - editRequired: false, - column: 1 + editRequired: false }, - /*source_username: { - labelBind: 'sourceUsernameLabel', - excludeModal: true, - type: 'text', - ngShow: "source.value == 'rackspace' || source.value == 'ec2'", - awRequiredWhen: {variable: "sourceUsernameRequired", init: "false" } - }, - source_password: { - labelBind: 'sourcePasswordLabel', - excludeModal: true, - type: 'password', - ngShow: "source.value == 'rackspace' || source.value == 'ec2'", - editRequired: false, - addRequired: false, - ngChange: "clearPWConfirm('source_password_confirm')", - ask: true, - clear: true, - associated: 'source_password_confirm', - autocomplete: false - }, - source_password_confirm: { - labelBind: 'sourcePasswordConfirmLabel', - type: 'password', - ngShow: "source.value == 'rackspace' || source.value == 'ec2'", - addRequired: false, - editRequired: false, - awPassMatch: true, - associated: 'source_password', - autocomplete: false - },*/ source_regions: { label: 'Regions', excludeModal: true, diff --git a/awx/ui/static/js/helpers/Credentials.js b/awx/ui/static/js/helpers/Credentials.js index 171ea4fb7b..239858e9d8 100644 --- a/awx/ui/static/js/helpers/Credentials.js +++ b/awx/ui/static/js/helpers/Credentials.js @@ -16,7 +16,7 @@ angular.module('CredentialsHelper', ['Utilities']) var form = params.form; var reset = params.reset; - // Set field lables + // Set field labels if (scope.kind.value !== 'ssh') { scope['usernameLabel'] = 'Username'; scope['passwordLabel'] = 'Password'; @@ -59,5 +59,24 @@ angular.module('CredentialsHelper', ['Utilities']) } } - }]); - \ No newline at end of file + }]) + + .factory('OwnerChange', [ function() { + return function(params) { + var scope = params.scope; + var owner = scope['owner']; + if (owner == 'team') { + scope['team_required'] = true; + scope['user_required'] = false; + scope['user'] = null; + scope['user_username'] = null; + } + else { + scope['team_required'] = false; + scope['user_required'] = true; + scope['team'] = null; + scope['team_name'] = null; + } + + } + }]); \ No newline at end of file diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index e84bfc836f..3a91f951f0 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -10,7 +10,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', - 'PromptDialog', 'InventorySummaryHelpDefinition', 'TreeSelector' + 'PromptDialog', 'InventorySummaryHelpDefinition', 'TreeSelector', 'CredentialsListDefinition' ]) .factory('GetSourceTypeOptions', [ 'Rest', 'ProcessErrors', 'GetBasePath', function(Rest, ProcessErrors, GetBasePath) { @@ -662,9 +662,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', - 'GetUpdateIntervalOptions', 'ClickNode', + 'GetUpdateIntervalOptions', 'ClickNode', 'LookUpInit', 'CredentialList', function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, GetUpdateIntervalOptions, ClickNode) { + GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, GetUpdateIntervalOptions, ClickNode, + LookUpInit, CredentialList) { return function(params) { var group_id = params.group_id; @@ -685,11 +686,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope.source = form.fields.source['default']; scope.parseType = 'yaml'; scope[form.fields['source_vars'].parseTypeName] = 'yaml'; - /*scope.sourcePasswordRequired = false; - scope.sourceUsernameRequired = false; - scope.sourceUsernameLabel = 'Username'; - scope.sourcePasswordLabel = 'Password'; - scope.sourcePasswordConfirmLabel = 'Confirm Password';*/ scope.sourcePathRequired = false; ParseTypeChange(scope); @@ -703,6 +699,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' for (var set in relatedSets) { scope.search(relatedSets[set].iterator); } + if (scope.variable_url) { // get group variables Rest.setUrl(scope.variable_url); @@ -785,6 +782,14 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' master[fld] = scope[fld]; } } + + LookUpInit({ + scope: scope, + form: form, + list: CredentialList, + field: 'credential' + }); + scope['group_update_url'] = data.related['update']; scope.sourceChange(); }) @@ -855,8 +860,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' var data = { group: group_id, source: scope['source'].value, source_path: scope['source_path'], - //source_username: scope['source_username'], - //source_password: scope['source_password'], + credential: scope['credential'], source_regions: scope['source_regions'], overwrite: scope['overwrite'], overwrite_vars: scope['overwrite_vars'], @@ -878,7 +882,14 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' if (typeof json_data !== 'object') { throw "failed to return an object!"; } - data.source_vars = JSON.stringify(json_data, undefined, '\t'); + + // Send JSON as a string + if ($.isEmptyObject(json_data)) { + data.source_vars = ""; + } + else { + data.source_vars = JSON.stringify(json_data, undefined, '\t'); + } } catch(err) { parseError = true; diff --git a/awx/ui/static/js/helpers/Lookup.js b/awx/ui/static/js/helpers/Lookup.js index c1e141bb07..f09c7fc211 100644 --- a/awx/ui/static/js/helpers/Lookup.js +++ b/awx/ui/static/js/helpers/Lookup.js @@ -21,7 +21,6 @@ angular.module('LookUpHelper', [ 'RestServices', 'Utilities', 'SearchHelper', 'P var scope = params.scope; // form scope var form = params.form; // form object - var current_item = params.current_item; //id of the item that should be selected on open var list = params.list; // list object var field = params.field; // form field var postAction = params.postAction //action to perform post user selection @@ -125,8 +124,8 @@ angular.module('LookUpHelper', [ 'RestServices', 'Utilities', 'SearchHelper', 'P } - if (!Empty(current_item)) { - listScope['toggle_' + list.iterator](current_item); + if (!Empty(scope[field])) { + listScope['toggle_' + list.iterator](scope[field]); } }); diff --git a/awx/ui/static/js/lists/Credentials.js b/awx/ui/static/js/lists/Credentials.js index 6866b23981..385ce23fdd 100644 --- a/awx/ui/static/js/lists/Credentials.js +++ b/awx/ui/static/js/lists/Credentials.js @@ -28,9 +28,6 @@ angular.module('CredentialsListDefinition', []) label: 'Description', excludeModal: true }, - kind: { - label: 'Kind' - }, team: { label: 'Team', ngBind: 'credential.team_name',