From 8a2be07ccbf9490db9b5e87ed05f06f730f8326d Mon Sep 17 00:00:00 2001 From: mabashian Date: Mon, 9 Jul 2018 15:52:58 -0400 Subject: [PATCH 1/4] Tweaked logic around the lookup modal and new form lookup fields in order to support dynamic breadcrumbs and selecting applications with the same name. --- .../add-applications.controller.js | 11 ++++-- .../add-edit-applications.view.html | 1 + .../edit-applications.controller.js | 6 ++++ .../credentials/add-credentials.controller.js | 12 +++++++ .../add-edit-credentials.view.html | 2 ++ .../edit-credentials.controller.js | 12 +++++++ .../tokens/users-tokens-add.controller.js | 11 ++++-- .../tokens/users-tokens-add.partial.html | 1 + .../lib/components/input/lookup.directive.js | 36 ++++++++++--------- .../lib/components/input/lookup.partial.html | 4 +-- 10 files changed, 73 insertions(+), 23 deletions(-) diff --git a/awx/ui/client/features/applications/add-applications.controller.js b/awx/ui/client/features/applications/add-applications.controller.js index c848bcd345..4318d29c82 100644 --- a/awx/ui/client/features/applications/add-applications.controller.js +++ b/awx/ui/client/features/applications/add-applications.controller.js @@ -1,4 +1,4 @@ -function AddApplicationsController (models, $state, strings) { +function AddApplicationsController (models, $state, strings, $scope) { const vm = this || {}; const { application, me, organization } = models; @@ -62,12 +62,19 @@ function AddApplicationsController (models, $state, strings) { vm.form.onSaveSuccess = res => { $state.go('applications.edit', { application_id: res.data.id }, { reload: true }); }; + + $scope.$watch('organization', () => { + if ($scope.organization) { + vm.form.organization._idFromModal = $scope.organization; + } + }); } AddApplicationsController.$inject = [ 'resolvedModels', '$state', - 'ApplicationsStrings' + 'ApplicationsStrings', + '$scope' ]; export default AddApplicationsController; diff --git a/awx/ui/client/features/applications/add-edit-applications.view.html b/awx/ui/client/features/applications/add-edit-applications.view.html index 1b77c009bf..873f75ded0 100644 --- a/awx/ui/client/features/applications/add-edit-applications.view.html +++ b/awx/ui/client/features/applications/add-edit-applications.view.html @@ -1,3 +1,4 @@ +
diff --git a/awx/ui/client/features/applications/edit-applications.controller.js b/awx/ui/client/features/applications/edit-applications.controller.js index 1bf6b8c91b..cf53a1abc3 100644 --- a/awx/ui/client/features/applications/edit-applications.controller.js +++ b/awx/ui/client/features/applications/edit-applications.controller.js @@ -43,6 +43,12 @@ function EditApplicationsController (models, $state, strings, $scope) { } }); + $scope.$watch('organization', () => { + if ($scope.organization) { + vm.form.organization._idFromModal = $scope.organization; + } + }); + if (isEditable) { vm.form = application.createFormSchema('put', { omit }); } else { diff --git a/awx/ui/client/features/credentials/add-credentials.controller.js b/awx/ui/client/features/credentials/add-credentials.controller.js index e0b575bf2d..6f99792a89 100644 --- a/awx/ui/client/features/credentials/add-credentials.controller.js +++ b/awx/ui/client/features/credentials/add-credentials.controller.js @@ -115,6 +115,18 @@ function AddCredentialsController (models, $state, $scope, strings, componentsSt return { obj, error }; }; + + $scope.$watch('organization', () => { + if ($scope.organization) { + vm.form.organization._idFromModal = $scope.organization; + } + }); + + $scope.$watch('credential_type', () => { + if ($scope.credential_type) { + vm.form.credential_type._idFromModal = $scope.credential_type; + } + }); } AddCredentialsController.$inject = [ diff --git a/awx/ui/client/features/credentials/add-edit-credentials.view.html b/awx/ui/client/features/credentials/add-edit-credentials.view.html index 277994cd81..43e56259aa 100644 --- a/awx/ui/client/features/credentials/add-edit-credentials.view.html +++ b/awx/ui/client/features/credentials/add-edit-credentials.view.html @@ -1,3 +1,5 @@ +
+
diff --git a/awx/ui/client/features/credentials/edit-credentials.controller.js b/awx/ui/client/features/credentials/edit-credentials.controller.js index 81b6ebe5fb..560b2605a6 100644 --- a/awx/ui/client/features/credentials/edit-credentials.controller.js +++ b/awx/ui/client/features/credentials/edit-credentials.controller.js @@ -32,6 +32,18 @@ function EditCredentialsController (models, $state, $scope, strings, componentsS } }); + $scope.$watch('organization', () => { + if ($scope.organization) { + vm.form.organization._idFromModal = $scope.organization; + } + }); + + $scope.$watch('credential_type', () => { + if ($scope.credential_type) { + vm.form.credential_type._idFromModal = $scope.credential_type; + } + }); + // Only exists for permissions compatibility $scope.credential_obj = credential.get(); diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.controller.js b/awx/ui/client/features/users/tokens/users-tokens-add.controller.js index 67e15fa0ad..26ce20e5f2 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add.controller.js +++ b/awx/ui/client/features/users/tokens/users-tokens-add.controller.js @@ -1,6 +1,6 @@ function AddTokensController ( models, $state, strings, Rest, Alert, Wait, GetBasePath, - $filter, ProcessErrors + $filter, ProcessErrors, $scope ) { const vm = this || {}; const { application } = models; @@ -94,6 +94,12 @@ function AddTokensController ( vm.form.onSaveSuccess = () => { $state.go('^', { user_id: $state.params.user_id }, { reload: true }); }; + + $scope.$watch('application', () => { + if ($scope.application) { + vm.form.application._idFromModal = $scope.application; + } + }); } AddTokensController.$inject = [ @@ -105,7 +111,8 @@ AddTokensController.$inject = [ 'Wait', 'GetBasePath', '$filter', - 'ProcessErrors' + 'ProcessErrors', + '$scope' ]; export default AddTokensController; diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html b/awx/ui/client/features/users/tokens/users-tokens-add.partial.html index 4b8343a0ed..f9055fd2e5 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html +++ b/awx/ui/client/features/users/tokens/users-tokens-add.partial.html @@ -1,3 +1,4 @@ +
diff --git a/awx/ui/client/lib/components/input/lookup.directive.js b/awx/ui/client/lib/components/input/lookup.directive.js index 0447d6b448..13632d8eb3 100644 --- a/awx/ui/client/lib/components/input/lookup.directive.js +++ b/awx/ui/client/lib/components/input/lookup.directive.js @@ -34,23 +34,20 @@ function AtInputLookupController (baseInputController, $q, $state) { } }; - scope.$watch(scope.state._resource, vm.watchResource); + // This should get triggered when the user selects something in the lookup modal and + // hits save to close the modal. This won't get triggered when the user types in + // a value in the input. + scope.$watch('state._idFromModal', () => { + if (scope.state._idFromModal && + (scope.state._idFromModal !== scope.state._value) + ) { + vm.search({ id: scope.state._idFromModal }); + } + }); vm.check(); }; - vm.watchResource = () => { - if (!scope[scope.state._resource]) { - return; - } - - if (scope[scope.state._resource] !== scope.state._value) { - scope.state._displayValue = scope[`${scope.state._resource}_name`]; - - vm.search(); - } - }; - vm.lookup = () => { const params = {}; @@ -62,6 +59,7 @@ function AtInputLookupController (baseInputController, $q, $state) { }; vm.reset = () => { + scope.state._idFromModal = undefined; scope.state._value = undefined; scope[scope.state._resource] = undefined; }; @@ -80,15 +78,20 @@ function AtInputLookupController (baseInputController, $q, $state) { vm.searchAfterDebounce(); }; - vm.search = () => { + vm.search = (searchParams) => { scope.state._touched = true; - if (scope.state._displayValue === '' && !scope.state._required) { + if (!scope.state._required && + scope.state._displayValue === '' && + !scope.state._idFromModal + ) { scope.state._value = null; return vm.check({ isValid: true }); } - return model.search({ [search.key]: scope.state._displayValue }, search.config) + searchParams = searchParams || { [search.key]: scope.state._displayValue }; + + return model.search(searchParams, search.config) .then(found => { if (!found) { vm.reset(); @@ -99,6 +102,7 @@ function AtInputLookupController (baseInputController, $q, $state) { scope[scope.state._resource] = model.get('id'); scope.state._value = model.get('id'); scope.state._displayValue = model.get('name'); + scope.state._idFromModal = undefined; }) .catch(() => vm.reset()) .finally(() => { diff --git a/awx/ui/client/lib/components/input/lookup.partial.html b/awx/ui/client/lib/components/input/lookup.partial.html index 24cde94edc..5a951cdb31 100644 --- a/awx/ui/client/lib/components/input/lookup.partial.html +++ b/awx/ui/client/lib/components/input/lookup.partial.html @@ -30,6 +30,4 @@ - -
- + From a30e2f93a6cf53a18a9d520cd86c28da7bf0d2df Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Fri, 6 Jul 2018 13:34:04 -0700 Subject: [PATCH 2/4] Adds org column to the application lookup modal, while on tokens form --- .../users-tokens-add-application.route.js | 15 ++++++--- .../list-generator/list-generator.factory.js | 33 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js b/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js index 13197ca11d..f647fc5edf 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js +++ b/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js @@ -42,14 +42,19 @@ export default { name: { key: true, label: 'Name', - columnClass: 'col-lg-4 col-md-6 col-sm-8 col-xs-8', + columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4', awToolTip: '{{application.description | sanitize}}', dataPlacement: 'top' }, - }, - actions: { - }, - fieldActions: { + organization: { + label: 'Organization', + columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4', + modalColumnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-4', + key: false, + ngBind: 'application.summary_fields.organization.name', + sourceModel: 'organization', + includeModal: true + } } })], Dataset: ['QuerySet', 'GetBasePath', '$stateParams', 'ListDefinition', diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js index b529cb2788..92fb28cf71 100644 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ b/awx/ui/client/src/shared/list-generator/list-generator.factory.js @@ -545,22 +545,27 @@ export default ['$compile', 'Attr', 'Icon', } } if (options.mode === 'lookup') { - let customClass = list.fields.name.modalColumnClass || ''; - html += ` - `; + for (fld in list.fields) { + if(fld === 'name' || _.has(list.fields[fld], 'includeModal')){ + let customClass = list.fields.name.modalColumnClass || ''; + html += ` + `; + } + + } if(list.fields.info) { - customClass = list.fields.name.modalColumnClass || ''; + let customClass = list.fields.name.modalColumnClass || ''; const infoHeaderClass = _.get(list.fields.info, 'infoHeaderClass', 'List-tableHeader--info'); html += ` Date: Mon, 9 Jul 2018 22:11:23 -0700 Subject: [PATCH 3/4] Cleanup to users' state tree In order to add additional route flexibility for the users-tokens states Removes unnecessary ui-view from form-generator Adjust nested ui-view target found during PR feedback --- .../users-tokens-add-application.route.js | 3 +- .../tokens/users-tokens-add.partial.html | 2 +- .../users/tokens/users-tokens-add.route.js | 2 +- awx/ui/client/src/shared/form-generator.js | 2 - .../src/users/add/users-add.controller.js | 5 +- .../src/users/edit/users-edit.controller.js | 77 +++++++++---------- awx/ui/client/src/users/main.js | 67 ++++++++++------ awx/ui/client/src/users/users.partial.html | 6 ++ awx/ui/client/src/users/users.route.js | 55 +++++++++++++ 9 files changed, 146 insertions(+), 73 deletions(-) create mode 100644 awx/ui/client/src/users/users.partial.html create mode 100644 awx/ui/client/src/users/users.route.js diff --git a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js b/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js index f647fc5edf..20173c260a 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js +++ b/awx/ui/client/features/users/tokens/users-tokens-add-application.route.js @@ -13,8 +13,7 @@ export default { } }, data: { - basePath: 'applications', - formChildState: true + basePath: 'applications' }, ncyBreadcrumb: { skip: true diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html b/awx/ui/client/features/users/tokens/users-tokens-add.partial.html index f9055fd2e5..25bd01a21a 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add.partial.html +++ b/awx/ui/client/features/users/tokens/users-tokens-add.partial.html @@ -9,7 +9,7 @@ - + diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.route.js b/awx/ui/client/features/users/tokens/users-tokens-add.route.js index 56effe1991..e8619b892c 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add.route.js +++ b/awx/ui/client/features/users/tokens/users-tokens-add.route.js @@ -30,7 +30,7 @@ export default { label: N_('CREATE TOKEN') }, views: { - 'preFormView@users.edit': { + 'preFormView@users': { templateUrl: addTemplate, controller: AddController, controllerAs: 'vm' diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 5aeb590a81..734aafee4e 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -167,7 +167,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat wrapPanel(html, ignorePanel){ if(ignorePanel) { return ` -
${html}
@@ -176,7 +175,6 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat } else { return ` -
${MessageBar(this.form)}
${html} diff --git a/awx/ui/client/src/users/add/users-add.controller.js b/awx/ui/client/src/users/add/users-add.controller.js index c822b7bf9d..7cc98629ed 100644 --- a/awx/ui/client/src/users/add/users-add.controller.js +++ b/awx/ui/client/src/users/add/users-add.controller.js @@ -14,10 +14,10 @@ const user_type_options = [ export default ['$scope', '$rootScope', 'UserForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'GetBasePath', - 'Wait', 'CreateSelect2', '$state', '$location', 'i18n', + 'Wait', 'CreateSelect2', '$state', '$location', 'i18n', 'canAdd', function($scope, $rootScope, UserForm, GenerateForm, Rest, Alert, ProcessErrors, ReturnToCaller, GetBasePath, Wait, CreateSelect2, - $state, $location, i18n) { + $state, $location, i18n, canAdd) { var defaultUrl = GetBasePath('organizations'), form = UserForm; @@ -28,6 +28,7 @@ export default ['$scope', '$rootScope', 'UserForm', 'GenerateForm', 'Rest', // apply form definition's default field values GenerateForm.applyDefaults(form, $scope); + $scope.canAdd = canAdd; $scope.isAddForm = true; $scope.ldap_user = false; $scope.not_ldap_user = !$scope.ldap_user; diff --git a/awx/ui/client/src/users/edit/users-edit.controller.js b/awx/ui/client/src/users/edit/users-edit.controller.js index f2294a1703..f44c34b2a8 100644 --- a/awx/ui/client/src/users/edit/users-edit.controller.js +++ b/awx/ui/client/src/users/edit/users-edit.controller.js @@ -14,10 +14,10 @@ const user_type_options = [ export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'Rest', 'ProcessErrors', 'GetBasePath', 'Wait', 'CreateSelect2', - '$state', 'i18n', 'resolvedModels', + '$state', 'i18n', 'resolvedModels', 'resourceData', function($scope, $rootScope, $stateParams, UserForm, Rest, ProcessErrors, - GetBasePath, Wait, CreateSelect2, $state, i18n, models) { - + GetBasePath, Wait, CreateSelect2, $state, i18n, models, resourceData) { + for (var i = 0; i < user_type_options.length; i++) { user_type_options[i].label = i18n._(user_type_options[i].label); } @@ -26,7 +26,10 @@ export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'Rest', var form = UserForm, master = {}, id = $stateParams.user_id, - defaultUrl = GetBasePath('users') + id; + defaultUrl = GetBasePath('users') + id, + user_obj = resourceData.data; + + $scope.breadcrumb.user_name = user_obj.username; init(); @@ -40,49 +43,39 @@ export default ['$scope', '$rootScope', '$stateParams', 'UserForm', 'Rest', $scope.user_type = user_type_options[0]; $scope.$watch('user_type', user_type_sync($scope)); $scope.$watch('is_superuser', hidePermissionsTabSmartSearchAndPaginationIfSuperUser($scope)); - Rest.setUrl(defaultUrl); - Wait('start'); - Rest.get(defaultUrl).then(({data}) => { - $scope.user_id = id; - $scope.ldap_user = (data.ldap_dn !== null && data.ldap_dn !== undefined && data.ldap_dn !== '') ? true : false; - $scope.not_ldap_user = !$scope.ldap_user; - master.ldap_user = $scope.ldap_user; - $scope.socialAuthUser = (data.auth.length > 0) ? true : false; - $scope.external_account = data.external_account; + $scope.user_id = id; + $scope.ldap_user = (user_obj.ldap_dn !== null && user_obj.ldap_dn !== undefined && user_obj.ldap_dn !== '') ? true : false; + $scope.not_ldap_user = !$scope.ldap_user; + master.ldap_user = $scope.ldap_user; + $scope.socialAuthUser = (user_obj.auth.length > 0) ? true : false; + $scope.external_account = user_obj.external_account; - $scope.user_type = $scope.user_type_options[0]; - $scope.is_system_auditor = false; - $scope.is_superuser = false; - if (data.is_system_auditor) { - $scope.user_type = $scope.user_type_options[1]; - $scope.is_system_auditor = true; - } - if (data.is_superuser) { - $scope.user_type = $scope.user_type_options[2]; - $scope.is_superuser = true; - } + $scope.user_type = $scope.user_type_options[0]; + $scope.is_system_auditor = false; + $scope.is_superuser = false; + if (user_obj.is_system_auditor) { + $scope.user_type = $scope.user_type_options[1]; + $scope.is_system_auditor = true; + } + if (user_obj.is_superuser) { + $scope.user_type = $scope.user_type_options[2]; + $scope.is_superuser = true; + } - $scope.user_obj = data; - $scope.name = data.username; + $scope.user_obj = user_obj; + $scope.name = user_obj.username; - CreateSelect2({ - element: '#user_user_type', - multiple: false - }); + CreateSelect2({ + element: '#user_user_type', + multiple: false + }); - $scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) { - $scope.canAdd = (val === false) ? false : true; - }); + $scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) { + $scope.canAdd = (val === false) ? false : true; + }); - setScopeFields(data); - Wait('stop'); - }) - .catch(({data, status}) => { - ProcessErrors($scope, data, status, null, { - hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Failed to retrieve user: %s. GET status: '), $stateParams.id) + status - }); - }); + setScopeFields(user_obj); + } function user_type_sync($scope) { diff --git a/awx/ui/client/src/users/main.js b/awx/ui/client/src/users/main.js index 3701d4f626..64222e3977 100644 --- a/awx/ui/client/src/users/main.js +++ b/awx/ui/client/src/users/main.js @@ -10,12 +10,11 @@ import UsersEdit from './edit/users-edit.controller'; import UserForm from './users.form'; import UserList from './users.list'; +import userListRoute from './users.route'; import UserTokensListRoute from '../../features/users/tokens/users-tokens-list.route'; import UserTokensAddRoute from '../../features/users/tokens/users-tokens-add.route'; import UserTokensAddApplicationRoute from '../../features/users/tokens/users-tokens-add-application.route'; -import { N_ } from '../i18n'; - export default angular.module('Users', []) .controller('UsersList', UsersList) @@ -29,20 +28,52 @@ angular.module('Users', []) let stateExtender = $stateExtenderProvider.$get(); function generateStateTree() { - let userTree = stateDefinitions.generateTree({ - parent: 'users', - modes: ['add', 'edit'], - list: 'UserList', + let userAdd = stateDefinitions.generateTree({ + name: 'users.add', + url: '/add', + modes: ['add'], form: 'UserForm', controllers: { - list: UsersList, - add: UsersAdd, - edit: UsersEdit + add: 'UsersAdd' + }, + resolve: { + add: { + canAdd: ['rbacUiControlService', '$state', function(rbacUiControlService, $state) { + return rbacUiControlService.canAdd('users') + .then(function(res) { + return res.canAdd; + }) + .catch(function() { + $state.go('users'); + }); + }], + resolvedModels: ['MeModel', '$q', function(Me, $q) { + const promises= { + me: new Me('get').then((me) => me.extend('get', 'admin_of_organizations')) + }; + + return $q.all(promises); + }] + } + } + }); + + let userEdit = stateDefinitions.generateTree({ + name: 'users.edit', + url: '/:user_id', + modes: ['edit'], + form: 'UserForm', + parent: 'users', + controllers: { + edit: 'UsersEdit' }, data: { activityStream: true, activityStreamTarget: 'user' }, + breadcrumbs: { + edit: "{{breadcrumb.user_name}}" + }, resolve: { edit: { resolvedModels: ['MeModel', '$q', function(Me, $q) { @@ -50,31 +81,21 @@ angular.module('Users', []) me: new Me('get').then((me) => me.extend('get', 'admin_of_organizations')) }; - return $q.all(promises); - }] - }, - list: { - resolvedModels: ['MeModel', '$q', function(Me, $q) { - const promises= { - me: new Me('get') - }; - return $q.all(promises); }] } }, - ncyBreadcrumb: { - label: N_('USERS') - } }); - + return Promise.all([ - userTree + userAdd, + userEdit ]).then((generated) => { return { states: _.reduce(generated, (result, definition) => { return result.concat(definition.states); }, [ + stateExtender.buildDefinition(userListRoute), stateExtender.buildDefinition(UserTokensListRoute), stateExtender.buildDefinition(UserTokensAddRoute), stateExtender.buildDefinition(UserTokensAddApplicationRoute) diff --git a/awx/ui/client/src/users/users.partial.html b/awx/ui/client/src/users/users.partial.html new file mode 100644 index 0000000000..41b78528d4 --- /dev/null +++ b/awx/ui/client/src/users/users.partial.html @@ -0,0 +1,6 @@ +
+ +
+
+
+
diff --git a/awx/ui/client/src/users/users.route.js b/awx/ui/client/src/users/users.route.js new file mode 100644 index 0000000000..80f581a93b --- /dev/null +++ b/awx/ui/client/src/users/users.route.js @@ -0,0 +1,55 @@ +import {templateUrl} from '../shared/template-url/template-url.factory'; +import { N_ } from '../i18n'; + +export default { + name: 'users', + route: '/users', + ncyBreadcrumb: { + label: N_('USERS') + }, + data: { + activityStream: true, + activityStreamTarget: 'user' + }, + params: { + user_search: { + value: { + page_size: 20, + order_by: 'username' + } + } + }, + views: { + '@': { + templateUrl: templateUrl('users/users') + }, + 'list@users': { + templateProvider: function(UserList, generateList) { + let html = generateList.build({ + list: UserList, + mode: 'edit' + }); + html = generateList.wrapPanel(html); + return html; + }, + controller: 'UsersList' + } + }, + searchPrefix: 'user', + resolve: { + Dataset: ['UserList', 'QuerySet', '$stateParams', 'GetBasePath', + function(list, qs, $stateParams, GetBasePath) { + let path = GetBasePath(list.basePath) || GetBasePath(list.name); + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ], + resolvedModels: ['MeModel', '$q', function(Me, $q) { + const promises= { + me: new Me('get') + }; + + return $q.all(promises); + }] + + } +}; From 02f6fa9b0aac5c0c1757fdf6b85b11c8e5d13729 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Wed, 11 Jul 2018 17:32:56 -0700 Subject: [PATCH 4/4] Prevents the user from adding a token for a user other than themselves It's possible to maninpulate the URL to get to the add-token screen for a different user, which gives the user the idea that they could possibly add a token for that user, which is not allowed. --- .../users/tokens/users-tokens-add.route.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/features/users/tokens/users-tokens-add.route.js b/awx/ui/client/features/users/tokens/users-tokens-add.route.js index e8619b892c..fe9548b79a 100644 --- a/awx/ui/client/features/users/tokens/users-tokens-add.route.js +++ b/awx/ui/client/features/users/tokens/users-tokens-add.route.js @@ -16,6 +16,21 @@ TokensDetailResolve.$inject = [ 'ApplicationModel' ]; +function isMeResolve ($rootScope, $stateParams, $state) { + // The user should not be able to add tokens for users other than + // themselves. Adding this redirect so that a user is not able to + // visit the add-token URL directly for a different user. + if (_.has($stateParams, 'user_id') && Number($stateParams.user_id) !== $rootScope.current_user.id) { + $state.go('users'); + } +} + +isMeResolve.$inject = [ + '$rootScope', + '$stateParams', + '$state' +]; + export default { url: '/add-token', name: 'users.edit.tokens.add', @@ -37,6 +52,7 @@ export default { } }, resolve: { - resolvedModels: TokensDetailResolve + resolvedModels: TokensDetailResolve, + isMe: isMeResolve } };