From 6e653c29e08bd27edf84e48c419ab33a2261346e Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Fri, 2 Sep 2016 11:31:18 -0400 Subject: [PATCH 1/8] ui implementation of crud-based ui hiding --- .../client/src/access/roleList.partial.html | 6 +- awx/ui/client/src/app.js | 6 ++ awx/ui/client/src/controllers/Credentials.js | 33 ++++++++ awx/ui/client/src/controllers/Projects.js | 32 ++++++- awx/ui/client/src/controllers/Teams.js | 32 ++++++- awx/ui/client/src/controllers/Users.js | 32 ++++++- awx/ui/client/src/forms/Credentials.js | 83 +++++++++++++------ awx/ui/client/src/forms/Inventories.js | 25 ++++-- awx/ui/client/src/forms/JobTemplates.js | 79 ++++++++++++------ awx/ui/client/src/forms/Organizations.js | 19 +++-- awx/ui/client/src/forms/Projects.js | 50 +++++++---- awx/ui/client/src/forms/Teams.js | 22 +++-- awx/ui/client/src/forms/Users.js | 35 +++++--- awx/ui/client/src/helpers/Parse.js | 2 +- awx/ui/client/src/helpers/ProjectPath.js | 14 ++-- .../add/inventory-add.controller.js | 9 ++ .../edit/inventory-edit.controller.js | 11 ++- .../list/inventory-list.controller.js | 12 +++ .../inventory-scripts/add/add.controller.js | 13 ++- .../inventory-scripts/edit/edit.controller.js | 11 +++ .../inventory-scripts.form.js | 17 +++- .../inventory-scripts.list.js | 17 +++- .../inventory-scripts/list/list.controller.js | 12 +++ .../add/job-templates-add.controller.js | 9 ++ .../edit/job-templates-edit.controller.js | 10 +++ .../list/job-templates-list.controller.js | 13 ++- .../survey-maker/survey-maker.block.less | 6 ++ awx/ui/client/src/lists/AllJobs.js | 6 +- awx/ui/client/src/lists/CompletedJobs.js | 5 +- awx/ui/client/src/lists/Credentials.js | 18 +++- awx/ui/client/src/lists/Inventories.js | 16 +++- awx/ui/client/src/lists/InventoryGroups.js | 18 ++-- awx/ui/client/src/lists/JobTemplates.js | 16 +++- awx/ui/client/src/lists/Projects.js | 23 +++-- awx/ui/client/src/lists/Schedules.js | 6 +- awx/ui/client/src/lists/Teams.js | 18 +++- awx/ui/client/src/lists/Users.js | 18 +++- .../src/notifications/notifications.list.js | 3 +- .../add/organizations-add.controller.js | 9 ++ .../edit/organizations-edit.controller.js | 10 +++ .../list/organizations-list.controller.js | 13 +++ .../list/organizations-list.partial.html | 11 +++ .../src/partials/survey-maker-modal.html | 17 ++-- awx/ui/client/src/shared/form-generator.js | 15 ++++ 44 files changed, 669 insertions(+), 163 deletions(-) diff --git a/awx/ui/client/src/access/roleList.partial.html b/awx/ui/client/src/access/roleList.partial.html index 1478c9dc37..365a20f061 100644 --- a/awx/ui/client/src/access/roleList.partial.html +++ b/awx/ui/client/src/access/roleList.partial.html @@ -1,13 +1,13 @@
-
{{ entry.name }} diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index d9101f6d22..512ad43595 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -840,6 +840,12 @@ var tower = angular.module('Tower', [ // If browser refresh, set the user_is_superuser value $rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser'); $rootScope.user_is_system_auditor = Authorization.getUserInfo('is_system_auditor'); + + Rest.setUrl($rootScope.current_user.related.admin_of_organizations); + Rest.get() + .success(function(data) { + $rootScope.current_user_admin_orgs = data.results.map(i => i.name); + }); // state 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')) { ConfigService.getConfig().then(function() { diff --git a/awx/ui/client/src/controllers/Credentials.js b/awx/ui/client/src/controllers/Credentials.js index 66b016dc50..53c4c001b4 100644 --- a/awx/ui/client/src/controllers/Credentials.js +++ b/awx/ui/client/src/controllers/Credentials.js @@ -17,6 +17,18 @@ export function CredentialsList($scope, $rootScope, $location, $log, SelectionInit, GetChoices, Wait, $state, $filter) { ClearScope(); + $scope.canAdd = false; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('credentials')); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + $scope.canEdit = true; + } + }); + Wait('start'); var list = CredentialList, @@ -139,6 +151,15 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, LookUpInit, OrganizationList, GetBasePath, GetChoices, Empty, KindChange, OwnerChange, FormSave, $state, CreateSelect2) { + Rest.setUrl(GetBasePath('credentials')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add a credential.', 'alert-info'); + } + }); + ClearScope(); // Inject dynamic view @@ -337,6 +358,7 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, } ClearScope(); + var defaultUrl = GetBasePath('credentials'), generator = GenerateForm, form = CredentialForm, @@ -344,6 +366,17 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, master = {}, id = $stateParams.credential_id, relatedSets = {}; + + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('credentials') + id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); $scope.id = id; diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index 60692d581e..5c0803c3ce 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -16,9 +16,20 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $stateParams, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, Refresh, Wait, GetChoices, Empty, Find, GetProjectIcon, GetProjectToolTip, $filter, $state) { - ClearScope(); + $scope.canAdd = false; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('projects')); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + $scope.canEdit = true; + } + }); + Wait('start'); var list = ProjectList, @@ -379,6 +390,15 @@ export function ProjectsAdd(Refresh, $scope, $rootScope, $compile, $location, $l OrganizationList, CredentialList, GetChoices, DebugForm, Wait, $state, CreateSelect2) { + Rest.setUrl(GetBasePath('projects')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add a project.', 'alert-info'); + } + }); + ClearScope(); // Inject dynamic view @@ -568,6 +588,16 @@ export function ProjectsEdit($scope, $rootScope, $compile, $location, $log, id = $stateParams.id, relatedSets = {}; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('projects') + id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + // remove "type" field from search options CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; diff --git a/awx/ui/client/src/controllers/Teams.js b/awx/ui/client/src/controllers/Teams.js index a8eed62bc5..f78a5f13c9 100644 --- a/awx/ui/client/src/controllers/Teams.js +++ b/awx/ui/client/src/controllers/Teams.js @@ -15,9 +15,20 @@ export function TeamsList($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, TeamList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit, Wait, $state, Refresh, $filter) { - ClearScope(); + $scope.canAdd = false; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('teams')); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + $scope.canEdit = true; + } + }); + var list = TeamList, defaultUrl = GetBasePath('teams'), generator = GenerateList, @@ -137,6 +148,15 @@ export function TeamsAdd($scope, $rootScope, $compile, $location, $log, ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //$scope. + Rest.setUrl(GetBasePath('teams')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add a team.', 'alert-info'); + } + }); + // Inject dynamic view var defaultUrl = GetBasePath('teams'), form = TeamForm, @@ -206,6 +226,16 @@ export function TeamsEdit($scope, $rootScope, $location, relatedSets = {}, set; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('teams') + id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + $scope.team_id = id; diff --git a/awx/ui/client/src/controllers/Users.js b/awx/ui/client/src/controllers/Users.js index 103e1d1c84..5e76269983 100644 --- a/awx/ui/client/src/controllers/Users.js +++ b/awx/ui/client/src/controllers/Users.js @@ -35,9 +35,20 @@ export function UsersList($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, UserList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, Wait, $state, Refresh, $filter) { - ClearScope(); + $scope.canAdd = false; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('users')); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + $scope.canEdit = true; + } + }); + var list = UserList, defaultUrl = GetBasePath('users'), generator = GenerateList, @@ -148,6 +159,15 @@ export function UsersAdd($scope, $rootScope, $compile, $location, $log, ReturnToCaller, ClearScope, GetBasePath, LookUpInit, OrganizationList, ResetForm, Wait, CreateSelect2, $state) { + Rest.setUrl(GetBasePath('users')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add a user.', 'alert-info'); + } + }); + ClearScope(); // Inject dynamic view @@ -272,6 +292,16 @@ export function UsersEdit($scope, $rootScope, $location, relatedSets = {}, set; + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('users') + id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); diff --git a/awx/ui/client/src/forms/Credentials.js b/awx/ui/client/src/forms/Credentials.js index d503f53905..4f2b262359 100644 --- a/awx/ui/client/src/forms/Credentials.js +++ b/awx/ui/client/src/forms/Credentials.js @@ -32,13 +32,15 @@ export default type: 'text', addRequired: true, editRequired: true, - autocomplete: false + autocomplete: false, + ngDisabled: '!canEdit' }, description: { label: 'Description', type: 'text', addRequired: false, - editRequired: false + editRequired: false, + ngDisabled: '!canEdit' }, organization: { addRequired: false, @@ -52,7 +54,8 @@ export default awPopOver: "

If no organization is given, the credential can only be used by the user that creates the credential. Organization admins and system administrators can assign an organization so that roles for the credential can be assigned to users and teams in that organization.

", dataTitle: 'Organization ', dataPlacement: 'bottom', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, kind: { label: 'Type', @@ -83,7 +86,8 @@ export default dataTitle: 'Type', dataPlacement: 'right', dataContainer: "body", - hasSubForm: true + hasSubForm: true, + ngDisabled: '!canEdit' }, access_key: { label: 'Access Key', @@ -96,12 +100,13 @@ export default autocomplete: false, apiField: 'username', subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, secret_key: { label: 'Secret Key', type: 'sensitive', ngShow: "kind.value == 'aws'", - ngDisabled: "secret_key_ask", + ngDisabled: "secret_key_ask || !canEdit", awRequiredWhen: { reqExpression: "aws_required", init: false @@ -123,7 +128,8 @@ export default dataTitle: 'STS Token', dataPlacement: 'right', dataContainer: "body", - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "host": { labelBind: 'hostLabel', @@ -139,7 +145,8 @@ export default reqExpression: 'host_required', init: false }, - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "subscription": { label: "Subscription ID", @@ -156,7 +163,8 @@ export default dataTitle: 'Subscription ID', dataPlacement: 'right', dataContainer: "body", - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "username": { labelBind: 'usernameLabel', @@ -168,7 +176,8 @@ export default init: false }, autocomplete: false, - subForm: "credentialSubForm" + subForm: "credentialSubForm", + ngDisabled: '!canEdit' }, "email_address": { labelBind: 'usernameLabel', @@ -183,7 +192,8 @@ export default dataTitle: 'Email', dataPlacement: 'right', dataContainer: "body", - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "api_key": { label: 'API Key', @@ -196,7 +206,8 @@ export default autocomplete: false, hasShowInputButton: true, clear: false, - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "password": { labelBind: 'passwordLabel', @@ -209,13 +220,14 @@ export default reqExpression: "password_required", init: false }, - subForm: "credentialSubForm" + subForm: "credentialSubForm", + ngDisabled: '!canEdit' }, "ssh_password": { label: 'Password', type: 'sensitive', ngShow: "kind.value == 'ssh'", - ngDisabled: "ssh_password_ask", + ngDisabled: "ssh_password_ask || !canEdit", addRequired: false, editRequired: false, subCheckbox: { @@ -247,7 +259,8 @@ export default dataTitle: 'Private Key', dataPlacement: 'right', dataContainer: "body", - subForm: "credentialSubForm" + subForm: "credentialSubForm", + ngDisabled: '!canEdit' }, "ssh_key_unlock": { label: 'Private Key Passphrase', @@ -255,7 +268,7 @@ export default ngShow: "kind.value == 'ssh' || kind.value == 'scm'", addRequired: false, editRequired: false, - ngDisabled: "keyEntered === false || ssh_key_unlock_ask", + ngDisabled: "keyEntered === false || ssh_key_unlock_ask || !canEdit", subCheckbox: { variable: 'ssh_key_unlock_ask', ngShow: "kind.value == 'ssh'", @@ -278,7 +291,8 @@ export default "sudo | su | pbrun | pfexec | runas
(defaults to sudo)

", dataPlacement: 'right', dataContainer: "body", - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "become_username": { labelBind: 'becomeUsernameLabel', @@ -287,13 +301,14 @@ export default addRequired: false, editRequired: false, autocomplete: false, - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "become_password": { labelBind: 'becomePasswordLabel', type: 'sensitive', ngShow: "(kind.value == 'ssh' && (become_method && become_method.value)) ", - ngDisabled: "become_password_ask", + ngDisabled: "become_password_ask || !canEdit", addRequired: false, editRequired: false, subCheckbox: { @@ -309,7 +324,8 @@ export default type: 'text', label: 'Client ID', subForm: 'credentialSubForm', - ngShow: "kind.value === 'azure_rm'" + ngShow: "kind.value === 'azure_rm'", + ngDisabled: '!canEdit' }, secret:{ type: 'sensitive', @@ -317,20 +333,23 @@ export default autocomplete: false, label: 'Client Secret', subForm: 'credentialSubForm', - ngShow: "kind.value === 'azure_rm'" + ngShow: "kind.value === 'azure_rm'", + ngDisabled: '!canEdit' }, tenant: { type: 'text', label: 'Tenant ID', subForm: 'credentialSubForm', - ngShow: "kind.value === 'azure_rm'" + ngShow: "kind.value === 'azure_rm'", + ngDisabled: '!canEdit' }, authorize: { label: 'Authorize', type: 'checkbox', ngChange: "toggleCallback('host_config_key')", subForm: 'credentialSubForm', - ngShow: "kind.value === 'net'" + ngShow: "kind.value === 'net'", + ngDisabled: '!canEdit' }, authorize_password: { label: 'Authorize Password', @@ -339,6 +358,7 @@ export default autocomplete: false, subForm: 'credentialSubForm', ngShow: "authorize && authorize !== 'false'", + ngDisabled: '!canEdit' }, "project": { labelBind: 'projectLabel', @@ -355,7 +375,8 @@ export default reqExpression: 'project_required', init: false }, - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "domain": { labelBind: 'domainLabel', @@ -371,13 +392,14 @@ export default dataContainer: "body", addRequired: false, editRequired: false, - subForm: 'credentialSubForm' + subForm: 'credentialSubForm', + ngDisabled: '!canEdit' }, "vault_password": { label: "Vault Password", type: 'sensitive', ngShow: "kind.value == 'ssh'", - ngDisabled: "vault_password_ask", + ngDisabled: "vault_password_ask || !canEdit", addRequired: false, editRequired: false, subCheckbox: { @@ -394,11 +416,17 @@ export default buttons: { cancel: { ngClick: 'formCancel()', + ngShow: 'canEdit' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!canEdit' }, save: { label: 'Save', ngClick: 'formSave()', //$scope.function to call on click, optional - ngDisabled: true //Disable when $pristine or $invalid, optional + ngDisabled: true, + ngShow: 'canEdit' //Disable when $pristine or $invalid, optional } }, @@ -421,7 +449,8 @@ export default label: 'Add', awToolTip: 'Add a permission', actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' + buttonContent: '+ ADD', + ngShow: 'canEdit' } }, diff --git a/awx/ui/client/src/forms/Inventories.js b/awx/ui/client/src/forms/Inventories.js index 6467bf28d3..c1d3c172d0 100644 --- a/awx/ui/client/src/forms/Inventories.js +++ b/awx/ui/client/src/forms/Inventories.js @@ -26,14 +26,16 @@ export default type: 'text', addRequired: true, editRequired: true, - capitalize: false + capitalize: false, + ngDisabled: '!canEdit' }, inventory_description: { realName: 'description', label: 'Description', type: 'text', addRequired: false, - editRequired: false + editRequired: false, + ngDisabled: '!canEdit' }, organization: { label: 'Organization', @@ -44,7 +46,8 @@ export default awRequiredWhen: { reqExpression: "organizationrequired", init: "true" - } + }, + ngDisabled: '!canEdit' }, variables: { label: 'Variables', @@ -63,17 +66,24 @@ export default '

View YAML examples at docs.ansible.com

', dataTitle: 'Inventory Variables', dataPlacement: 'right', - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' // TODO: get working } }, buttons: { cancel: { - ngClick: 'formCancel()' + ngClick: 'formCancel()', + ngShow: 'canEdit' + }, + close: { + ngClick: 'formCancel()', + ngHide: 'canEdit' }, save: { ngClick: 'formSave()', - ngDisabled: true + ngDisabled: true, + ngShow: 'canEdit' } }, @@ -94,7 +104,8 @@ export default label: 'Add', awToolTip: 'Add a permission', actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' + buttonContent: '+ ADD', + ngShow: 'canEdit' } }, diff --git a/awx/ui/client/src/forms/JobTemplates.js b/awx/ui/client/src/forms/JobTemplates.js index 5d56907c88..d7a6c81bfa 100644 --- a/awx/ui/client/src/forms/JobTemplates.js +++ b/awx/ui/client/src/forms/JobTemplates.js @@ -27,14 +27,16 @@ export default type: 'text', addRequired: true, editRequired: true, - column: 1 + column: 1, + ngDisabled: '!canEdit' }, description: { label: 'Description', type: 'text', addRequired: false, editRequired: false, - column: 1 + column: 1, + ngDisabled: '!canEdit' }, job_type: { label: 'Job Type', @@ -56,7 +58,8 @@ export default variable: 'ask_job_type_on_launch', ngShow: "!job_type.value || job_type.value !== 'scan'", text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, inventory: { label: 'Inventory', @@ -78,7 +81,8 @@ export default variable: 'ask_inventory_on_launch', ngShow: "!job_type.value || job_type.value !== 'scan'", text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, project: { label: 'Project', @@ -100,12 +104,13 @@ export default dataTitle: 'Project', dataPlacement: 'right', dataContainer: "body", + ngDisabled: '!canEdit' }, playbook: { label: 'Playbook', type:'select', ngOptions: 'book for book in playbook_options track by book', - ngDisabled: "job_type.value === 'scan' && project_name === 'Default'", + ngDisabled: "(job_type.value === 'scan' && project_name === 'Default') || !canEdit", id: 'playbook-select', awRequiredWhen: { reqExpression: "playbookrequired", @@ -138,7 +143,8 @@ export default subCheckbox: { variable: 'ask_credential_on_launch', text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, cloud_credential: { label: 'Cloud Credential', @@ -153,7 +159,8 @@ export default "running playbook, allowing provisioning into the cloud without manually passing parameters to the included modules.

", dataTitle: 'Cloud Credential', dataPlacement: 'right', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, network_credential: { label: 'Network Credential', @@ -167,7 +174,8 @@ export default awPopOver: "

Network credentials are used by Ansible networking modules to connect to and manage networking devices.

", dataTitle: 'Network Credential', dataPlacement: 'right', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, forks: { label: 'Forks', @@ -186,7 +194,8 @@ export default ' target=\"_blank\">ansible configuration file.

', dataTitle: 'Forks', dataPlacement: 'right', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' // TODO: get working }, limit: { label: 'Limit', @@ -203,7 +212,8 @@ export default subCheckbox: { variable: 'ask_limit_on_launch', text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, verbosity: { label: 'Verbosity', @@ -216,7 +226,8 @@ export default awPopOver: "

Control the level of output ansible will produce as the playbook executes.

", dataTitle: 'Verbosity', dataPlacement: 'right', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, job_tags: { label: 'Job Tags', @@ -235,7 +246,8 @@ export default subCheckbox: { variable: 'ask_tags_on_launch', text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, skip_tags: { label: 'Skip Tags', @@ -254,7 +266,8 @@ export default subCheckbox: { variable: 'ask_skip_tags_on_launch', text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' }, checkbox_group: { label: 'Options', @@ -270,7 +283,8 @@ export default dataPlacement: 'right', dataTitle: 'Become Privilege Escalation', dataContainer: "body", - labelClass: 'stack-inline' + labelClass: 'stack-inline', + ngDisabled: '!canEdit' }, { name: 'allow_callbacks', label: 'Allow Provisioning Callbacks', @@ -284,7 +298,8 @@ export default dataPlacement: 'right', dataTitle: 'Allow Provisioning Callbacks', dataContainer: "body", - labelClass: 'stack-inline' + labelClass: 'stack-inline', + ngDisabled: '!canEdit' }] }, callback_url: { @@ -299,7 +314,8 @@ export default awPopOverWatch: "callback_help", dataPlacement: 'top', dataTitle: 'Provisioning Callback URL', - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, host_config_key: { label: 'Host Config Key', @@ -312,7 +328,8 @@ export default awPopOverWatch: "callback_help", dataPlacement: 'right', dataTitle: "Host Config Key", - dataContainer: "body" + dataContainer: "body", + ngDisabled: '!canEdit' }, labels: { label: 'Labels', @@ -325,7 +342,8 @@ export default dataTitle: 'Labels', dataPlacement: 'right', awPopOver: "

Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs in the Tower display.

", - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' }, variables: { label: 'Extra Variables', @@ -348,14 +366,15 @@ export default subCheckbox: { variable: 'ask_variables_on_launch', text: 'Prompt on launch' - } + }, + ngDisabled: '!canEdit' // TODO: get working } }, buttons: { //for now always generates @@ -31,13 +32,23 @@
+
-
+
-
+
-
+
PREVIEW
@@ -56,13 +56,13 @@ {{question.question_description}}
- +   -
+
@@ -80,9 +80,10 @@
- - - + + + +
diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 66c4f750b8..821857e3f6 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -865,6 +865,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += ">"; html += " Date: Fri, 2 Sep 2016 13:38:10 -0400 Subject: [PATCH 2/8] conditionally show add button for job templates --- awx/ui/client/src/lists/JobTemplates.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/lists/JobTemplates.js b/awx/ui/client/src/lists/JobTemplates.js index 398a490d65..ce75bf3dd6 100644 --- a/awx/ui/client/src/lists/JobTemplates.js +++ b/awx/ui/client/src/lists/JobTemplates.js @@ -55,7 +55,8 @@ export default basePaths: ['job_templates'], awToolTip: 'Create a new template', actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' + buttonContent: '+ ADD', + ngShow: 'canAdd' } }, From 1f586091e2334e3012189d0d03e6555b1f7cf4eb Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 6 Sep 2016 17:10:16 -0400 Subject: [PATCH 3/8] groups and hosts rbac conditional showing in ui implementation --- awx/ui/client/src/forms/Groups.js | 41 +++++++++++++------ awx/ui/client/src/forms/Hosts.js | 14 +++++-- .../manage/groups/groups-edit.controller.js | 15 ++++++- .../manage/groups/groups-list.controller.js | 16 +++++++- .../manage/hosts/hosts-edit.controller.js | 14 ++++++- .../manage/hosts/hosts-list.controller.js | 18 +++++++- .../manage/inventory-manage.controller.js | 35 +++++++++------- awx/ui/client/src/lists/InventoryGroups.js | 14 ++++++- awx/ui/client/src/lists/InventoryHosts.js | 19 +++++++-- 9 files changed, 142 insertions(+), 44 deletions(-) diff --git a/awx/ui/client/src/forms/Groups.js b/awx/ui/client/src/forms/Groups.js index e3327d442e..ece74417a4 100644 --- a/awx/ui/client/src/forms/Groups.js +++ b/awx/ui/client/src/forms/Groups.js @@ -26,14 +26,16 @@ export default type: 'text', addRequired: true, editRequired: true, - tab: 'properties' + tab: 'properties', + ngDisabled: '!canEdit' }, description: { label: 'Description', type: 'text', addRequired: false, editRequired: false, - tab: 'properties' + tab: 'properties', + ngDisabled: '!canEdit' }, variables: { label: 'Variables', @@ -65,7 +67,8 @@ export default ngChange: 'sourceChange(source)', addRequired: false, editRequired: false, - ngModel: 'source' + ngModel: 'source', + ngDisabled: '!canEdit' }, credential: { label: 'Cloud Credential', @@ -77,7 +80,8 @@ export default awRequiredWhen: { reqExpression: "cloudCredentialRequired", init: "false" - } + }, + ngDisabled: '!canEdit' }, source_regions: { label: 'Regions', @@ -92,7 +96,8 @@ export default awPopOver: "

Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " + "or choose All to include all regions. Tower will only be updated with Hosts associated with the selected regions." + "

", - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' }, instance_filters: { label: 'Instance Filters', @@ -112,7 +117,8 @@ export default "
tag:Name=test*
\n" + "

View the Describe Instances documentation " + "for a complete list of supported filters.

", - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' }, group_by: { label: 'Only Group By', @@ -137,7 +143,8 @@ export default "
  • VPC ID: vpcs » vpc-5ca1ab1e
  • " + "
  • Tag None: tags » tag_none
  • " + "

    If blank, all groups above are created except Instance ID.

    ", - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' }, inventory_script: { label : "Custom Inventory Script", @@ -149,6 +156,7 @@ export default addRequired: true, editRequired: true, ngRequired: "source && source.value === 'custom'", + ngDisabled: '!canEdit', }, custom_variables: { id: 'custom_variables', @@ -269,7 +277,8 @@ export default dataTitle: 'Overwrite', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options', + ngDisabled: '!canEdit' }, { name: 'overwrite_vars', label: 'Overwrite Variables', @@ -283,7 +292,8 @@ export default dataTitle: 'Overwrite Variables', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options', + ngDisabled: '!canEdit' }, { name: 'update_on_launch', label: 'Update on Launch', @@ -296,7 +306,8 @@ export default dataTitle: 'Update on Launch', dataContainer: 'body', dataPlacement: 'right', - labelClass: 'checkbox-options' + labelClass: 'checkbox-options', + ngDisabled: '!canEdit' }] }, update_cache_timeout: { @@ -321,11 +332,17 @@ export default buttons: { cancel: { - ngClick: 'formCancel()' + ngClick: 'formCancel()', + ngShow: 'canEdit' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!canEdit' }, save: { ngClick: 'formSave()', - ngDisabled: true + ngDisabled: true, + ngShow: 'canEdit' } }, diff --git a/awx/ui/client/src/forms/Hosts.js b/awx/ui/client/src/forms/Hosts.js index 0da34d3e2e..99caaa2b6b 100644 --- a/awx/ui/client/src/forms/Hosts.js +++ b/awx/ui/client/src/forms/Hosts.js @@ -46,13 +46,15 @@ export default "", dataTitle: 'Host Name', dataPlacement: 'right', - dataContainer: 'body' + dataContainer: 'body', + ngDisabled: '!canEdit' }, description: { label: 'Description', type: 'text', addRequired: false, - editRequired: false + editRequired: false, + ngDisabled: '!canEdit' }, variables: { label: 'Variables', @@ -83,10 +85,16 @@ export default buttons: { cancel: { ngClick: 'formCancel()', + ngShow: 'canEdit' + }, + close: { + ngClick: 'formCancel()', + ngShow: '!canEdit' }, save: { ngClick: 'formSave()', - ngDisabled: true + ngDisabled: true, + ngShow: 'canEdit' } }, diff --git a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js index 941789f39d..fbcd4a00c1 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js @@ -7,10 +7,21 @@ export default ['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ToggleNotification', 'ParseVariableString', 'ParseTypeChange', 'GenerateForm', 'LookUpInit', 'RelatedSearchInit', 'RelatedPaginateInit', 'NotificationsListInit', - 'GroupManageService','GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'groupData', 'inventorySourceData', + 'GroupManageService','GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'groupData', 'inventorySourceData', 'Rest', function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ToggleNotification, ParseVariableString, ParseTypeChange, GenerateForm, LookUpInit, RelatedSearchInit, RelatedPaginateInit, NotificationsListInit, - GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, groupData, inventorySourceData){ + GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, groupData, inventorySourceData, Rest){ + + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('groups') + $stateParams.group_id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + var generator = GenerateForm, form = GroupForm(); diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js index ca56eeddd4..2b3889de18 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js @@ -5,13 +5,25 @@ *************************************************/ export default ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', - 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', + 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Rest', 'GetBasePath', function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, - InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg){ + InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg, Rest, GetBasePath){ var list = InventoryGroups, view = generateList, pageSize = 20; $scope.inventory_id = $stateParams.inventory_id; + + $scope.canAdd = false; + + Rest.setUrl(GetBasePath('inventory') + $scope.inventory_id + "/groups"); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + } + }); + + // The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope. // In this case, we don't want to incidentally bind to this scope when editing a host or a group. See: // https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js index 9098e53333..435968ccce 100644 --- a/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-edit.controller.js @@ -5,8 +5,18 @@ *************************************************/ export default - ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'host', - function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){ + ['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'host', 'GetBasePath', 'Rest', + function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host, GetBasePath, Rest){ + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('hosts') + $stateParams.host_id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + var generator = GenerateForm, form = HostForm; $scope.parseType = 'yaml'; diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js index 3c48cf8603..88219d9715 100644 --- a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js @@ -5,12 +5,26 @@ *************************************************/ export default ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryHosts', 'generateList', 'InventoryManageService', 'HostManageService', - 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData', '$filter', + 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData', '$filter', 'Rest', 'GetBasePath', function($scope, $rootScope, $state, $stateParams, InventoryHosts, generateList, InventoryManageService, HostManageService, - hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData, $filter){ + hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData, $filter, Rest, GetBasePath){ + var list = InventoryHosts, view = generateList, pageSize = 20; + + $scope.canAdd = false; + + $scope.inventory_id = $stateParams.inventory_id; + + Rest.setUrl(GetBasePath('inventory') + $scope.inventory_id + "/hosts"); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + $scope.canAdd = true; + } + }); + // The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope. // In this case, we don't want to incidentally bind to this scope when editing a host or a group. See: // https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js index aceb174363..f3201d475a 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.controller.js +++ b/awx/ui/client/src/inventories/manage/inventory-manage.controller.js @@ -3,21 +3,26 @@ * * All Rights Reserved *************************************************/ - export default - ['$scope', '$state', function($scope, $state){ - $scope.groupsSelected = false; - $scope.hostsSelected = false; - $scope.hostsSelectedItems = []; - $scope.groupsSelectedItems = []; - $scope.setAdhocPattern = function(){ - var pattern = _($scope.groupsSelectedItems) - .concat($scope.hostsSelectedItems) - .map(function(item){ - return item.name; - }).value().join(':'); - $state.go('inventoryManage.adhoc', {pattern: pattern}); - }; +export default + ['$scope', '$state', 'inventoryData', function($scope, $state, inventoryData){ + $scope.groupsSelected = false; + $scope.hostsSelected = false; + $scope.hostsSelectedItems = []; + $scope.groupsSelectedItems = []; + + $scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc; + + $scope.setAdhocPattern = function(){ + var pattern = _($scope.groupsSelectedItems) + .concat($scope.hostsSelectedItems) + .map(function(item){ + return item.name; + }).value().join(':'); + + $state.go('inventoryManage.adhoc', {pattern: pattern}); + }; + $scope.$watchGroup(['groupsSelected', 'hostsSelected'], function(newVals) { $scope.adhocCommandTooltip = (newVals[0] || newVals[1]) ? "Run a command on the selected inventory" : "Select an inventory source by clicking the check box beside it. The inventory source can be a single group or host, a selection of multiple hosts, or a selection of multiple groups."; }); - }]; + }]; diff --git a/awx/ui/client/src/lists/InventoryGroups.js b/awx/ui/client/src/lists/InventoryGroups.js index 66e74e97c0..d228982dd3 100644 --- a/awx/ui/client/src/lists/InventoryGroups.js +++ b/awx/ui/client/src/lists/InventoryGroups.js @@ -143,7 +143,8 @@ export default actionClass: 'btn List-buttonDefault', buttonContent: 'RUN COMMANDS', showTipWhenDisabled: true, - tooltipInnerClass: "Tooltip-wide" + tooltipInnerClass: "Tooltip-wide", + ngShow: 'canAdhoc' // TODO: set up a tip watcher and change text based on when // things are selected/not selected. This is started and // commented out in the inventory controller within the watchers. @@ -155,7 +156,8 @@ export default ngClick: "createGroup()", awToolTip: "Create a new group", actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD GROUP' + buttonContent: '+ ADD GROUP', + ngShow: 'canAdd' } }, @@ -208,6 +210,14 @@ export default dataPlacement: "top", ngShow: "group.summary_fields.user_capabilities.edit" }, + view: { + //label: 'Edit', + mode: 'all', + ngClick: "editGroup(group.id)", + awToolTip: 'View group', + dataPlacement: "top", + ngShow: "!group.summary_fields.user_capabilities.edit" + }, "delete": { //label: 'Delete', mode: 'all', diff --git a/awx/ui/client/src/lists/InventoryHosts.js b/awx/ui/client/src/lists/InventoryHosts.js index 1c01a77021..1a01ae1ca2 100644 --- a/awx/ui/client/src/lists/InventoryHosts.js +++ b/awx/ui/client/src/lists/InventoryHosts.js @@ -78,21 +78,31 @@ export default mode: 'all', ngClick: "copyMoveHost(host.id)", awToolTip: 'Copy or move host to another group', - dataPlacement: "top" + dataPlacement: "top", + ngShow: 'host.summary_fields.user_capabilities.edit' }, edit: { //label: 'Edit', ngClick: "editHost(host.id)", icon: 'icon-edit', awToolTip: 'Edit host', - dataPlacement: 'top' + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.edit' + }, + view: { + //label: 'Edit', + ngClick: "editHost(host.id)", + awToolTip: 'View host', + dataPlacement: 'top', + ngShow: '!host.summary_fields.user_capabilities.edit' }, "delete": { //label: 'Delete', ngClick: "deleteHost(host.id, host.name)", icon: 'icon-trash', awToolTip: 'Delete host', - dataPlacement: 'top' + dataPlacement: 'top', + ngShow: 'host.summary_fields.user_capabilities.delete' } }, @@ -122,7 +132,8 @@ export default ngClick: "createHost()", awToolTip: "Create a new host", actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD HOST' + buttonContent: '+ ADD HOST', + ngShow: 'canAdd' } } From ab3588fd934eb65ceedfb99642c0b949c89210ff Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 7 Sep 2016 15:27:11 -0400 Subject: [PATCH 4/8] more updates to ui crud --- awx/ui/client/src/controllers/Jobs.js | 9 +- .../inventory-scripts/edit/edit.controller.js | 7 +- .../inventory-scripts.form.js | 14 +-- awx/ui/client/src/lists/AllJobs.js | 7 +- awx/ui/client/src/lists/ScheduledJobs.js | 13 ++- awx/ui/client/src/lists/Schedules.js | 10 +- .../management-jobs/card/card.partial.html | 2 + .../src/notifications/add/add.controller.js | 13 ++- .../src/notifications/edit/edit.controller.js | 10 ++ .../list.controller.js | 12 ++ .../notificationTemplates.form.js | 104 ++++++++++++------ .../notificationTemplates.list.js | 20 +++- .../src/scheduler/scheduler.controller.js | 13 +++ .../src/scheduler/schedulerAdd.controller.js | 1 - 14 files changed, 180 insertions(+), 55 deletions(-) diff --git a/awx/ui/client/src/controllers/Jobs.js b/awx/ui/client/src/controllers/Jobs.js index 3f0e3bdcfd..0e2f46f736 100644 --- a/awx/ui/client/src/controllers/Jobs.js +++ b/awx/ui/client/src/controllers/Jobs.js @@ -13,7 +13,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $stateParams, ClearScope, LoadSchedulesScope, - LoadJobsScope, AllJobsList, ScheduledJobsList, GetChoices, GetBasePath, Wait) { + LoadJobsScope, AllJobsList, ScheduledJobsList, GetChoices, GetBasePath, Wait, $state) { ClearScope(); @@ -61,6 +61,11 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa } } jobs_scope = $scope.$new(true); + + jobs_scope.viewJob = function (id) { + $state.transitionTo('jobDetail', {id: id}); + }; + jobs_scope.showJobType = true; LoadJobsScope({ parent_scope: $scope, @@ -153,4 +158,4 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa JobsListController.$inject = ['$rootScope', '$log', '$scope', '$compile', '$stateParams', 'ClearScope', 'LoadSchedulesScope', 'LoadJobsScope', -'AllJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait']; +'AllJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', '$state']; diff --git a/awx/ui/client/src/inventory-scripts/edit/edit.controller.js b/awx/ui/client/src/inventory-scripts/edit/edit.controller.js index 41d3309cc1..40a6eda216 100644 --- a/awx/ui/client/src/inventory-scripts/edit/edit.controller.js +++ b/awx/ui/client/src/inventory-scripts/edit/edit.controller.js @@ -17,6 +17,7 @@ export default LookUpInit, OrganizationList, inventory_script, $scope, $state ) { + var generator = GenerateForm, id = inventory_script.id, form = inventoryScriptsFormObject, @@ -24,13 +25,15 @@ export default url = GetBasePath('inventory_scripts'); - $scope.canEdit = false; + $scope.canEditInvScripts = false; Rest.setUrl(GetBasePath('inventory_scripts') + id); Rest.options() .success(function(data) { if (data.actions.PUT) { - $scope.canEdit = true; + $scope.canEditInvScripts = true; + } else { + $scope.canEditInvScripts = false; } }); diff --git a/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js b/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js index 082126a975..6a2f538421 100644 --- a/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js +++ b/awx/ui/client/src/inventory-scripts/inventory-scripts.form.js @@ -25,14 +25,14 @@ export default function() { addRequired: true, editRequired: true, capitalize: false, - ngDisabled: '!canEdit' + ngDisabled: '!canEditInvScripts' }, description: { label: 'Description', type: 'text', addRequired: false, editRequired: false, - ngDisabled: '!canEdit' + ngDisabled: '!canEditInvScripts' }, organization: { label: 'Organization', @@ -44,7 +44,7 @@ export default function() { sourceModel: 'organization', sourceField: 'name', ngClick: 'lookUpOrganization()', - ngDisabled: '!canEdit' + ngDisabled: '!canEditInvScripts' }, script: { label: 'Custom Script', @@ -54,7 +54,7 @@ export default function() { addRequired: true, editRequired: true, awDropFile: true, - ngDisabled: '!canEdit', + ngDisabled: '!canEditInvScripts', rows: 10, awPopOver: "

    Drag and drop your custom inventory script file here or create one in the field to import your custom inventory. " + "

    Script must begin with a hashbang sequence: i.e.... #!/usr/bin/env python

    ", @@ -67,16 +67,16 @@ export default function() { buttons: { //for now always generates @@ -27,6 +28,7 @@ diff --git a/awx/ui/client/src/notifications/add/add.controller.js b/awx/ui/client/src/notifications/add/add.controller.js index 0b58f2e257..122d822cf4 100644 --- a/awx/ui/client/src/notifications/add/add.controller.js +++ b/awx/ui/client/src/notifications/add/add.controller.js @@ -9,14 +9,23 @@ export default 'NotificationsFormObject', 'ProcessErrors', 'GetBasePath', 'Empty', 'GenerateForm', 'SearchInit' , 'PaginateInit', 'LookUpInit', 'OrganizationList', '$scope', '$state', 'CreateSelect2', 'GetChoices', - 'NotificationsTypeChange', 'ParseTypeChange', + 'NotificationsTypeChange', 'ParseTypeChange', 'Alert', function( $rootScope, pagination, $compile, SchedulerInit, Rest, Wait, NotificationsFormObject, ProcessErrors, GetBasePath, Empty, GenerateForm, SearchInit, PaginateInit, LookUpInit, OrganizationList, $scope, $state, CreateSelect2, GetChoices, - NotificationsTypeChange, ParseTypeChange + NotificationsTypeChange, ParseTypeChange, Alert ) { + Rest.setUrl(GetBasePath('projects')); + Rest.options() + .success(function(data) { + if (!data.actions.POST) { + $state.go("^"); + Alert('Permission Error', 'You do not have permission to add a notification template.', 'alert-info'); + } + }); + var generator = GenerateForm, form = NotificationsFormObject, url = GetBasePath('notification_templates'); diff --git a/awx/ui/client/src/notifications/edit/edit.controller.js b/awx/ui/client/src/notifications/edit/edit.controller.js index 44c50a71ce..0f9250ed29 100644 --- a/awx/ui/client/src/notifications/edit/edit.controller.js +++ b/awx/ui/client/src/notifications/edit/edit.controller.js @@ -25,6 +25,16 @@ export default master = {}, url = GetBasePath('notification_templates'); + $scope.canEdit = false; + + Rest.setUrl(GetBasePath('notification_templates') + id); + Rest.options() + .success(function(data) { + if (data.actions.PUT) { + $scope.canEdit = true; + } + }); + $scope.notification_template = notification_template; generator.inject(form, { mode: 'edit' , diff --git a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js index 04265f1181..40570e7aa8 100644 --- a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js +++ b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js @@ -24,6 +24,18 @@ export default scope: scope }); + scope.canAdd = false; + scope.canEdit = false; + + Rest.setUrl(GetBasePath('notification_templates')); + Rest.options() + .success(function(data) { + if (data.actions.POST) { + scope.canAdd = true; + scope.canEdit = true;; + } + }); + scope.removePostRefresh = scope.$on('PostRefresh', function () { Wait('stop'); if (scope.notification_templates) { diff --git a/awx/ui/client/src/notifications/notificationTemplates.form.js b/awx/ui/client/src/notifications/notificationTemplates.form.js index cd0ff9d945..e4003e52b8 100644 --- a/awx/ui/client/src/notifications/notificationTemplates.form.js +++ b/awx/ui/client/src/notifications/notificationTemplates.form.js @@ -27,13 +27,15 @@ export default function() { type: 'text', addRequired: true, editRequired: true, - capitalize: false + capitalize: false, + ngDisabled: '!canEdit' }, description: { label: 'Description', type: 'text', addRequired: false, - editRequired: false + editRequired: false, + ngDisabled: '!canEdit' }, organization: { label: 'Organization', @@ -44,7 +46,8 @@ export default function() { awRequiredWhen: { reqExpression: "organizationrequired", init: "true" - } + }, + ngDisabled: '!canEdit' }, notification_type: { label: 'Type', @@ -54,13 +57,15 @@ export default function() { class: 'NotificationsForm-typeSelect', ngOptions: 'type.label for type in notification_type_options track by type.value', ngChange: 'typeChange()', - hasSubForm: true + hasSubForm: true, + ngDisabled: '!canEdit' }, username: { label: 'Username', type: 'text', ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, host: { @@ -71,7 +76,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, sender: { label: 'Sender Email', @@ -81,7 +87,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, recipients: { label: 'Recipient List', @@ -97,7 +104,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'email' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, password: { labelBind: 'passwordLabel', @@ -108,7 +116,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'email' || notification_type.value == 'irc' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, port: { labelBind: 'portLabel', @@ -122,7 +131,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'email' || notification_type.value == 'irc'", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, channels: { label: 'Destination Channels', @@ -138,7 +148,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'slack'", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, rooms: { label: 'Destination Channels', @@ -154,7 +165,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'hipchat'", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, token: { labelBind: 'tokenLabel', @@ -165,7 +177,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'slack' || notification_type.value == 'pagerduty' || notification_type.value == 'hipchat'", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, account_token: { label: 'Account Token', @@ -176,7 +189,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, from_number: { label: 'Source Phone Number', @@ -188,7 +202,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, to_numbers: { label: 'Destination SMS Number', @@ -204,7 +219,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, account_sid: { label: 'Account SID', @@ -214,7 +230,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'twilio' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, subdomain: { label: 'Pagerduty subdomain', @@ -224,7 +241,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, service_key: { label: 'API Service/Integration Key', @@ -234,7 +252,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, client_name: { label: 'Client Identifier', @@ -244,7 +263,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'pagerduty' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, message_from: { label: 'Label to be shown with notification', @@ -254,7 +274,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, api_url: { label: 'API URL', @@ -265,7 +286,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, color: { label: 'Notification Color', @@ -277,13 +299,15 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, notify: { label: 'Notify Channel', type: 'checkbox', ngShow: "notification_type.value == 'hipchat' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, url: { label: 'Target URL', @@ -293,7 +317,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'webhook' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, headers: { label: 'HTTP Headers', @@ -313,7 +338,8 @@ export default function() { '

    ', dataPlacement: 'right', ngShow: "notification_type.value == 'webhook' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, server: { label: 'IRC Server Address', @@ -323,7 +349,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, nickname: { label: 'IRC Nick', @@ -333,7 +360,8 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, targets: { label: 'Destination Channels or Users', @@ -349,13 +377,15 @@ export default function() { init: "false" }, ngShow: "notification_type.value == 'irc' ", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, use_ssl: { label: 'SSL Connection', type: 'checkbox', ngShow: "notification_type.value == 'irc'", - subForm: 'typeSubForm' + subForm: 'typeSubForm', + ngDisabled: '!canEdit' }, checkbox_group: { label: 'Options', @@ -367,13 +397,15 @@ export default function() { label: 'Use TLS', type: 'checkbox', ngShow: "notification_type.value == 'email' ", - labelClass: 'checkbox-options stack-inline' + labelClass: 'checkbox-options stack-inline', + ngDisabled: '!canEdit' }, { name: 'use_ssl', label: 'Use SSL', type: 'checkbox', ngShow: "notification_type.value == 'email'", - labelClass: 'checkbox-options stack-inline' + labelClass: 'checkbox-options stack-inline', + ngDisabled: '!canEdit' }] } }, @@ -381,9 +413,15 @@ export default function() { buttons: { //for now always generates
    -
    +
    -
    +
    -
    +
    PREVIEW
    @@ -56,13 +56,13 @@ {{question.question_description}}
    - +   -
    +
    @@ -80,10 +80,10 @@
    - - - - + + + +
    diff --git a/awx/ui/client/src/scheduler/scheduler.controller.js b/awx/ui/client/src/scheduler/scheduler.controller.js index bba15c65b6..16681e1b66 100644 --- a/awx/ui/client/src/scheduler/scheduler.controller.js +++ b/awx/ui/client/src/scheduler/scheduler.controller.js @@ -50,14 +50,12 @@ export default [ url += "schedules/"; $scope.canAdd = false; - $scope.canEdit = false; Rest.setUrl(url); Rest.options() .success(function(data) { if (data.actions.POST) { $scope.canAdd = true; - $scope.canEdit = true; } }); From a7cbfdc24264692f62cc467d6421ee8abeeb61cf Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 13 Sep 2016 16:14:26 -0400 Subject: [PATCH 7/8] update canAdd and move org admin scope var off of rootScope --- awx/ui/client/src/app.js | 5 ---- awx/ui/client/src/controllers/Credentials.js | 20 ------------- awx/ui/client/src/controllers/Projects.js | 13 ++++---- awx/ui/client/src/controllers/Teams.js | 13 ++++---- awx/ui/client/src/controllers/Users.js | 13 ++++---- .../list/inventory-list.controller.js | 13 ++++---- .../manage/groups/groups-list.controller.js | 13 ++++---- .../manage/hosts/hosts-list.controller.js | 17 +++++------ .../inventory-scripts/list/list.controller.js | 13 ++++---- .../list/job-templates-list.controller.js | 13 ++++---- awx/ui/client/src/lists/Credentials.js | 3 +- .../list.controller.js | 13 ++++---- .../shared/notification-list-init.factory.js | 12 ++++++-- .../list/organizations-list.controller.js | 13 ++++---- .../src/scheduler/scheduler.controller.js | 13 ++++---- awx/ui/client/src/shared/main.js | 4 ++- awx/ui/client/src/shared/rbacUiControl.js | 30 +++++++++++++++++++ 17 files changed, 101 insertions(+), 120 deletions(-) create mode 100644 awx/ui/client/src/shared/rbacUiControl.js diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 512ad43595..bde0407b20 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -841,11 +841,6 @@ var tower = angular.module('Tower', [ $rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser'); $rootScope.user_is_system_auditor = Authorization.getUserInfo('is_system_auditor'); - Rest.setUrl($rootScope.current_user.related.admin_of_organizations); - Rest.get() - .success(function(data) { - $rootScope.current_user_admin_orgs = data.results.map(i => i.name); - }); // state 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')) { ConfigService.getConfig().then(function() { diff --git a/awx/ui/client/src/controllers/Credentials.js b/awx/ui/client/src/controllers/Credentials.js index 1696756ed3..aed17aee32 100644 --- a/awx/ui/client/src/controllers/Credentials.js +++ b/awx/ui/client/src/controllers/Credentials.js @@ -17,16 +17,6 @@ export function CredentialsList($scope, $rootScope, $location, $log, SelectionInit, GetChoices, Wait, $state, $filter) { ClearScope(); - $scope.canAdd = false; - - Rest.setUrl(GetBasePath('credentials')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } - }); - Wait('start'); var list = CredentialList, @@ -148,16 +138,6 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, ReturnToCaller, ClearScope, GenerateList, SearchInit, PaginateInit, LookUpInit, OrganizationList, GetBasePath, GetChoices, Empty, KindChange, OwnerChange, FormSave, $state, CreateSelect2) { - - Rest.setUrl(GetBasePath('credentials')); - Rest.options() - .success(function(data) { - if (!data.actions.POST) { - $state.go("^"); - Alert('Permission Error', 'You do not have permission to add a credential.', 'alert-info'); - } - }); - ClearScope(); // Inject dynamic view diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index 2aa6d1ab9a..6c882cdd13 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -15,17 +15,14 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, ProjectList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, Refresh, Wait, GetChoices, Empty, - Find, GetProjectIcon, GetProjectToolTip, $filter, $state) { + Find, GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService) { ClearScope(); $scope.canAdd = false; - Rest.setUrl(GetBasePath('projects')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd('projects') + .then(function(canAdd) { + $scope.canAdd = canAdd; }); Wait('start'); @@ -378,7 +375,7 @@ ProjectsList.$inject = ['$scope', '$rootScope', '$location', '$log', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'Refresh', 'Wait', 'GetChoices', 'Empty', 'Find', - 'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state' + 'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state', 'rbacUiControlService' ]; diff --git a/awx/ui/client/src/controllers/Teams.js b/awx/ui/client/src/controllers/Teams.js index 08ed3c5f8f..ca30f84699 100644 --- a/awx/ui/client/src/controllers/Teams.js +++ b/awx/ui/client/src/controllers/Teams.js @@ -14,17 +14,14 @@ export function TeamsList($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, TeamList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, - SelectionInit, Wait, $state, Refresh, $filter) { + SelectionInit, Wait, $state, Refresh, $filter, rbacUiControlService) { ClearScope(); $scope.canAdd = false; - Rest.setUrl(GetBasePath('teams')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd('teams') + .then(function(canAdd) { + $scope.canAdd = canAdd; }); var list = TeamList, @@ -135,7 +132,7 @@ TeamsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'TeamList', 'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait', - '$state', 'Refresh', '$filter' + '$state', 'Refresh', '$filter', 'rbacUiControlService' ]; diff --git a/awx/ui/client/src/controllers/Users.js b/awx/ui/client/src/controllers/Users.js index 7033e6333d..0a00ed97c3 100644 --- a/awx/ui/client/src/controllers/Users.js +++ b/awx/ui/client/src/controllers/Users.js @@ -34,17 +34,14 @@ function user_type_sync($scope) { export function UsersList($scope, $rootScope, $location, $log, $stateParams, Rest, Alert, UserList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit, - Wait, $state, Refresh, $filter) { + Wait, $state, Refresh, $filter, rbacUiControlService) { ClearScope(); $scope.canAdd = false; - Rest.setUrl(GetBasePath('users')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd('users') + .then(function(canAdd) { + $scope.canAdd = canAdd; }); var list = UserList, @@ -145,7 +142,7 @@ UsersList.$inject = ['$scope', '$rootScope', '$location', '$log', '$stateParams', 'Rest', 'Alert', 'UserList', 'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'SelectionInit', 'Wait', '$state', - 'Refresh', '$filter' + 'Refresh', '$filter', 'rbacUiControlService' ]; diff --git a/awx/ui/client/src/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories/list/inventory-list.controller.js index d70217e6c5..a8d5fc73e7 100644 --- a/awx/ui/client/src/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories/list/inventory-list.controller.js @@ -14,16 +14,13 @@ function InventoriesList($scope, $rootScope, $location, $log, $stateParams, $compile, $filter, sanitizeFilter, Rest, Alert, InventoryList, generateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, Wait, - Find, Empty, $state) { + Find, Empty, $state, rbacUiControlService) { $scope.canAdd = false; - Rest.setUrl(GetBasePath('inventory')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd('inventory') + .then(function(canAdd) { + $scope.canAdd = canAdd; }); var list = InventoryList, @@ -386,4 +383,4 @@ function InventoriesList($scope, $rootScope, $location, $log, export default ['$scope', '$rootScope', '$location', '$log', '$stateParams', '$compile', '$filter', 'sanitizeFilter', 'Rest', 'Alert', 'InventoryList', 'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', - 'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', InventoriesList]; + 'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', InventoriesList]; diff --git a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js index 2b3889de18..a2f843793b 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-list.controller.js @@ -5,9 +5,9 @@ *************************************************/ export default ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus', - 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Rest', 'GetBasePath', + 'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Rest', 'GetBasePath', 'rbacUiControlService', function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus, - InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg, Rest, GetBasePath){ + InventoryManageService, groupsUrl, SearchInit, PaginateInit, GetSyncStatusMsg, GetHostsStatusMsg, Rest, GetBasePath, rbacUiControlService){ var list = InventoryGroups, view = generateList, pageSize = 20; @@ -15,12 +15,9 @@ $scope.canAdd = false; - Rest.setUrl(GetBasePath('inventory') + $scope.inventory_id + "/groups"); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups") + .then(function(canAdd) { + $scope.canAdd = canAdd; }); diff --git a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js index 88219d9715..f42b9c39b3 100644 --- a/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js +++ b/awx/ui/client/src/inventories/manage/hosts/hosts-list.controller.js @@ -5,24 +5,21 @@ *************************************************/ export default ['$scope', '$rootScope', '$state', '$stateParams', 'InventoryHosts', 'generateList', 'InventoryManageService', 'HostManageService', - 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData', '$filter', 'Rest', 'GetBasePath', + 'hostsUrl', 'SearchInit', 'PaginateInit', 'SetStatus', 'Prompt', 'Wait', 'inventoryData', '$filter', 'Rest', 'GetBasePath', 'rbacUiControlService', function($scope, $rootScope, $state, $stateParams, InventoryHosts, generateList, InventoryManageService, HostManageService, - hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData, $filter, Rest, GetBasePath){ + hostsUrl, SearchInit, PaginateInit, SetStatus, Prompt, Wait, inventoryData, $filter, Rest, GetBasePath, rbacUiControlService){ var list = InventoryHosts, view = generateList, pageSize = 20; - $scope.canAdd = false; - $scope.inventory_id = $stateParams.inventory_id; - Rest.setUrl(GetBasePath('inventory') + $scope.inventory_id + "/hosts"); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + $scope.canAdd = false; + + rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/hosts") + .then(function(canAdd) { + $scope.canAdd = canAdd; }); // The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope. diff --git a/awx/ui/client/src/inventory-scripts/list/list.controller.js b/awx/ui/client/src/inventory-scripts/list/list.controller.js index f8ad33e7db..08e0db5f67 100644 --- a/awx/ui/client/src/inventory-scripts/list/list.controller.js +++ b/awx/ui/client/src/inventory-scripts/list/list.controller.js @@ -7,11 +7,11 @@ export default [ '$rootScope','Wait', 'generateList', 'inventoryScriptsListObject', 'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' , 'ProcessErrors', - 'Prompt', '$state', '$filter', + 'Prompt', '$state', '$filter', 'rbacUiControlService', function( $rootScope,Wait, GenerateList, inventoryScriptsListObject, GetBasePath, SearchInit, PaginateInit, - Rest, ProcessErrors, Prompt, $state, $filter + Rest, ProcessErrors, Prompt, $state, $filter, rbacUiControlService ) { var scope = $rootScope.$new(), defaultUrl = GetBasePath('inventory_scripts'), @@ -20,12 +20,9 @@ export default scope.canAdd = false; - Rest.setUrl(GetBasePath('inventory_scripts')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - scope.canAdd = true; - } + rbacUiControlService.canAdd("inventory_scripts") + .then(function(canAdd) { + scope.canAdd = canAdd; }); view.inject( list, { diff --git a/awx/ui/client/src/job-templates/list/job-templates-list.controller.js b/awx/ui/client/src/job-templates/list/job-templates-list.controller.js index a2d4eedf4e..4e50f43fec 100644 --- a/awx/ui/client/src/job-templates/list/job-templates-list.controller.js +++ b/awx/ui/client/src/job-templates/list/job-templates-list.controller.js @@ -10,25 +10,22 @@ export default 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList', 'LookUpInit', 'InitiatePlaybookRun', 'Wait', '$compile', - '$state', '$filter', + '$state', '$filter', 'rbacUiControlService', function( $scope, $rootScope, $location, $log, $stateParams, Rest, Alert, JobTemplateList, GenerateList, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, JobTemplateForm, CredentialList, LookUpInit, InitiatePlaybookRun, - Wait, $compile, $state, $filter + Wait, $compile, $state, $filter, rbacUiControlService ) { ClearScope(); $scope.canAdd = false; - Rest.setUrl(GetBasePath('job_templates')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd("job_templates") + .then(function(canAdd) { + $scope.canAdd = canAdd; }); var list = JobTemplateList, diff --git a/awx/ui/client/src/lists/Credentials.js b/awx/ui/client/src/lists/Credentials.js index bebfc7ccfb..d9496b1807 100644 --- a/awx/ui/client/src/lists/Credentials.js +++ b/awx/ui/client/src/lists/Credentials.js @@ -58,8 +58,7 @@ export default ngClick: 'addCredential()', awToolTip: 'Create a new credential', actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD', - ngShow: 'canAdd' + buttonContent: '+ ADD' } }, diff --git a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js index 09bf1393a8..7fc279534b 100644 --- a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js +++ b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js @@ -8,12 +8,12 @@ export default [ '$rootScope','Wait', 'generateList', 'NotificationTemplatesList', 'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' , 'ProcessErrors', 'Prompt', '$state', 'GetChoices', 'Empty', 'Find', - 'ngToast', '$compile', '$filter', + 'ngToast', '$compile', '$filter', 'rbacUiControlService', function( $rootScope,Wait, GenerateList, NotificationTemplatesList, GetBasePath, SearchInit, PaginateInit, Rest, ProcessErrors, Prompt, $state, GetChoices, Empty, Find, ngToast, - $compile, $filter) { + $compile, $filter, rbacUiControlService) { var scope = $rootScope.$new(), defaultUrl = GetBasePath('notification_templates'), list = NotificationTemplatesList, @@ -26,12 +26,9 @@ export default scope.canAdd = false; - Rest.setUrl(GetBasePath('notification_templates')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - scope.canAdd = true; - } + rbacUiControlService.canAdd("notification_templates") + .then(function(canAdd) { + scope.canAdd = canAdd; }); scope.removePostRefresh = scope.$on('PostRefresh', function () { diff --git a/awx/ui/client/src/notifications/shared/notification-list-init.factory.js b/awx/ui/client/src/notifications/shared/notification-list-init.factory.js index ba13bea4c9..e8a711e783 100644 --- a/awx/ui/client/src/notifications/shared/notification-list-init.factory.js +++ b/awx/ui/client/src/notifications/shared/notification-list-init.factory.js @@ -15,13 +15,21 @@ */ export default ['Wait', 'GetBasePath', 'ProcessErrors', 'Rest', 'GetChoices', - '$state', - function(Wait, GetBasePath, ProcessErrors, Rest, GetChoices, $state) { + '$state', '$rootScope', + function(Wait, GetBasePath, ProcessErrors, Rest, GetChoices, $state, $rootScope) { return function(params) { var scope = params.scope, url = params.url, id = params.id; + scope.current_user_admin_orgs = []; + + Rest.setUrl($rootScope.current_user.related.admin_of_organizations); + Rest.get() + .success(function(data) { + scope.current_user_admin_orgs = data.results.map(i => i.name); + }); + scope.addNotificationTemplate = function(){ $state.go('notifications.add'); }; diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js index 00a5bb9569..13ea87ce82 100644 --- a/awx/ui/client/src/organizations/list/organizations-list.controller.js +++ b/awx/ui/client/src/organizations/list/organizations-list.controller.js @@ -8,23 +8,20 @@ export default ['$stateParams', '$scope', '$rootScope', '$location', '$log', '$compile', 'Rest', 'PaginateInit', 'SearchInit', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', - '$state', 'generateList', 'Refresh', '$filter', + '$state', 'generateList', 'Refresh', '$filter', 'rbacUiControlService', function($stateParams, $scope, $rootScope, $location, $log, $compile, Rest, PaginateInit, SearchInit, OrganizationList, Alert, Prompt, ClearScope, ProcessErrors, GetBasePath, Wait, - $state, generateList, Refresh, $filter) { + $state, generateList, Refresh, $filter, rbacUiControlService) { ClearScope(); $scope.canAdd = false; - Rest.setUrl(GetBasePath('organizations')); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd("organizations") + .then(function(canAdd) { + $scope.canAdd = canAdd; }); var defaultUrl = GetBasePath('organizations'), diff --git a/awx/ui/client/src/scheduler/scheduler.controller.js b/awx/ui/client/src/scheduler/scheduler.controller.js index 16681e1b66..db8eaa7b29 100644 --- a/awx/ui/client/src/scheduler/scheduler.controller.js +++ b/awx/ui/client/src/scheduler/scheduler.controller.js @@ -14,11 +14,11 @@ export default [ '$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest', 'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Wait', - 'Find', 'LoadSchedulesScope', 'GetChoices', '$q', '$state', + 'Find', 'LoadSchedulesScope', 'GetChoices', '$q', '$state', 'rbacUiControlService', function ($scope, $compile, $location, $stateParams, SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope, GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices, - $q, $state) { + $q, $state, rbacUiControlService) { var schedList = _.cloneDeep(SchedulesList); ClearScope(); @@ -51,12 +51,9 @@ export default [ $scope.canAdd = false; - Rest.setUrl(url); - Rest.options() - .success(function(data) { - if (data.actions.POST) { - $scope.canAdd = true; - } + rbacUiControlService.canAdd(url) + .then(function(canAdd) { + $scope.canAdd = canAdd; }); schedList.well = true; diff --git a/awx/ui/client/src/shared/main.js b/awx/ui/client/src/shared/main.js index 6279fbf1e7..60c812e12c 100644 --- a/awx/ui/client/src/shared/main.js +++ b/awx/ui/client/src/shared/main.js @@ -11,12 +11,14 @@ import lodashAsPromised from './lodash-as-promised'; import stringFilters from './string-filters/main'; import truncatedText from './truncated-text.directive'; import stateExtender from './stateExtender.provider'; +import rbacUiControl from './rbacUiControl'; export default angular.module('shared', [listGenerator.name, pagination.name, stringFilters.name, - 'ui.router' + 'ui.router', + rbacUiControl.name ]) .factory('lodashAsPromised', lodashAsPromised) .directive('truncatedText', truncatedText) diff --git a/awx/ui/client/src/shared/rbacUiControl.js b/awx/ui/client/src/shared/rbacUiControl.js new file mode 100644 index 0000000000..7ec06d66c2 --- /dev/null +++ b/awx/ui/client/src/shared/rbacUiControl.js @@ -0,0 +1,30 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +export default + angular.module('rbacUiControl', []) + .service('rbacUiControlService', ['$q', 'GetBasePath', 'Rest', function($q, GetBasePath, Rest){ + this.canAdd = function(apiPath) { + var canAddVal = $q.defer(); + + if (apiPath.indexOf("api/v1") > -1) { + Rest.setUrl(apiPath); + } else { + Rest.setUrl(GetBasePath(apiPath)); + } + + Rest.options() + .success(function(data) { + if (data.actions.POST) { + canAddVal.resolve(true); + } else { + canAddVal.reject(false); + } + }); + + return canAddVal.promise; + }; + }]); From 2482f6c46b24c44cddad1ff3fa8eeb00a48aca23 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Thu, 15 Sep 2016 13:20:19 -0400 Subject: [PATCH 8/8] add wait start and stop to add service --- awx/ui/client/src/shared/rbacUiControl.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/shared/rbacUiControl.js b/awx/ui/client/src/shared/rbacUiControl.js index 7ec06d66c2..4c8a00d827 100644 --- a/awx/ui/client/src/shared/rbacUiControl.js +++ b/awx/ui/client/src/shared/rbacUiControl.js @@ -6,7 +6,7 @@ export default angular.module('rbacUiControl', []) - .service('rbacUiControlService', ['$q', 'GetBasePath', 'Rest', function($q, GetBasePath, Rest){ + .service('rbacUiControlService', ['$q', 'GetBasePath', 'Rest', 'Wait', function($q, GetBasePath, Rest, Wait){ this.canAdd = function(apiPath) { var canAddVal = $q.defer(); @@ -16,6 +16,7 @@ export default Rest.setUrl(GetBasePath(apiPath)); } + Wait("start"); Rest.options() .success(function(data) { if (data.actions.POST) { @@ -23,6 +24,7 @@ export default } else { canAddVal.reject(false); } + Wait("stop"); }); return canAddVal.promise;