diff --git a/awx/ui/client/src/configuration/auth-form/configuration-auth.controller.js b/awx/ui/client/src/configuration/auth-form/configuration-auth.controller.js index 9d450717f3..c38183599e 100644 --- a/awx/ui/client/src/configuration/auth-form/configuration-auth.controller.js +++ b/awx/ui/client/src/configuration/auth-form/configuration-auth.controller.js @@ -6,6 +6,7 @@ export default [ '$scope', + '$rootScope', '$state', '$stateParams', '$timeout', @@ -26,6 +27,7 @@ export default [ 'ParseTypeChange', function( $scope, + $rootScope, $state, $stateParams, $timeout, @@ -138,7 +140,6 @@ export default [ }, ]; var forms = _.pluck(authForms, 'formDef'); - _.each(forms, function(form) { var keys = _.keys(form.fields); _.each(keys, function(key) { @@ -156,6 +157,8 @@ export default [ } addFieldInfo(form, key); }); + // Disable the save button for non-superusers + form.buttons.save.disabled = 'vm.updateProhibited'; }); function addFieldInfo(form, key) { @@ -167,7 +170,8 @@ export default [ dataPlacement: 'top', placeholder: ConfigurationUtils.formatPlaceholder($scope.$parent.configDataResolve[key].placeholder, key) || null, dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required + required: $scope.$parent.configDataResolve[key].required, + ngDisabled: $rootScope.user_is_system_auditor }); } diff --git a/awx/ui/client/src/configuration/configuration.block.less b/awx/ui/client/src/configuration/configuration.block.less index edf80e01a8..de4dae2e2c 100644 --- a/awx/ui/client/src/configuration/configuration.block.less +++ b/awx/ui/client/src/configuration/configuration.block.less @@ -1,4 +1,5 @@ @import "./client/src/shared/branding/colors.default.less"; +@import "../shared/branding/colors.less"; .Form-resetValue, .Form-resetFile { text-transform: uppercase; @@ -49,3 +50,24 @@ input#filePickerText { border-radius: 0 5px 5px 0; background-color: #fff; } + +// Messagebar for system auditor role notifications +.Section-messageBar { + width: 120%; + margin-left: -20px; + padding: 10px; + color: @white; + background-color: @default-link; +} + +.Section-messageBar--close { + position: absolute; + right: 0; + background: none; + border: none; + color: @info-close; +} + +.Section-messageBar--close:hover { + color: @white; +} diff --git a/awx/ui/client/src/configuration/configuration.controller.js b/awx/ui/client/src/configuration/configuration.controller.js index 5bc6ea6415..35d19a5611 100644 --- a/awx/ui/client/src/configuration/configuration.controller.js +++ b/awx/ui/client/src/configuration/configuration.controller.js @@ -362,6 +362,12 @@ export default [ $scope.toggleForm = function(key) { + if($rootScope.user_is_system_auditor) { + // Block system auditors from making changes + event.preventDefault(); + return; + } + $scope[key] = !$scope[key]; Wait('start'); var payload = {}; @@ -425,16 +431,58 @@ export default [ triggerModal(msg, title, buttons); }; + var show_auditor_bar; + if($rootScope.user_is_system_auditor && Store('show_auditor_bar') !== false) { + show_auditor_bar = true; + } else { + show_auditor_bar = false; + } + + var updateMessageBarPrefs = function() { + vm.show_auditor_bar = false; + Store('show_auditor_bar', vm.show_auditor_bar); + }; + + var closeMessageBar = function() { + var msg = 'Are you sure you want to hide the notification bar?'; + var title = 'Warning: Closing notification bar'; + var buttons = [{ + label: "Cancel", + "class": "btn Form-cancelButton", + "id": "formmodal-cancel-button", + onClick: function() { + $('#FormModal-dialog').dialog('close'); + } + }, { + label: "OK", + onClick: function() { + $('#FormModal-dialog').dialog('close'); + updateMessageBarPrefs(); + }, + "class": "btn btn-primary", + "id": "formmodal-save-button" + }]; + triggerModal(msg, title, buttons); + }; + + var updateProhibited = true; + if($rootScope.user_is_superuser) { + updateProhibited = false; + } + angular.extend(vm, { activeTab: activeTab, activeTabCheck: activeTabCheck, + closeMessageBar: closeMessageBar, currentForm: currentForm, formCancel: formCancel, formTracker: formTracker, formSave: formSave, populateFromApi: populateFromApi, resetAllConfirm: resetAllConfirm, - triggerModal: triggerModal + show_auditor_bar: show_auditor_bar, + triggerModal: triggerModal, + updateProhibited: updateProhibited }); } ]; diff --git a/awx/ui/client/src/configuration/configuration.partial.html b/awx/ui/client/src/configuration/configuration.partial.html index 31a14d9e51..42beab808c 100644 --- a/awx/ui/client/src/configuration/configuration.partial.html +++ b/awx/ui/client/src/configuration/configuration.partial.html @@ -1,3 +1,9 @@ +
+ + System auditors have read-only permissions in this section. + +
+
diff --git a/awx/ui/client/src/configuration/configuration.service.js b/awx/ui/client/src/configuration/configuration.service.js index 5c86f3beae..9204638c8c 100644 --- a/awx/ui/client/src/configuration/configuration.service.js +++ b/awx/ui/client/src/configuration/configuration.service.js @@ -4,19 +4,27 @@ * All Rights Reserved *************************************************/ -export default ['GetBasePath', 'ProcessErrors', '$q', '$http', 'Rest', - function(GetBasePath, ProcessErrors, $q, $http, Rest) { +export default ['$rootScope', 'GetBasePath', 'ProcessErrors', '$q', '$http', 'Rest', + function($rootScope, GetBasePath, ProcessErrors, $q, $http, Rest) { var url = GetBasePath('settings'); return { getConfigurationOptions: function() { var deferred = $q.defer(); + var returnData; + Rest.setUrl(url + '/all'); Rest.options() .success(function(data) { - var returnData = data.actions.PUT; + if($rootScope.is_superuser) { + returnData = data.actions.PUT; + } else { + returnData = data.actions.GET; + } + //LICENSE is read only, returning here explicitly for display - returnData.LICENSE = data.actions.GET.LICENSE; + // Removing LICENSE display until 3.2 or later + //returnData.LICENSE = data.actions.GET.LICENSE; deferred.resolve(returnData); }) .error(function(error) { diff --git a/awx/ui/client/src/configuration/jobs-form/configuration-jobs.controller.js b/awx/ui/client/src/configuration/jobs-form/configuration-jobs.controller.js index 726457bc4e..c242e97da1 100644 --- a/awx/ui/client/src/configuration/jobs-form/configuration-jobs.controller.js +++ b/awx/ui/client/src/configuration/jobs-form/configuration-jobs.controller.js @@ -6,6 +6,7 @@ export default [ '$scope', + '$rootScope', '$state', '$timeout', 'ConfigurationJobsForm', @@ -16,6 +17,7 @@ export default [ 'i18n', function( $scope, + $rootScope, $state, $timeout, ConfigurationJobsForm, @@ -37,6 +39,9 @@ export default [ }); }); + // Disable the save button for non-superusers + form.buttons.save.disabled = 'vm.updateProhibited'; + var keys = _.keys(form.fields); _.each(keys, function(key) { addFieldInfo(form, key); @@ -50,7 +55,8 @@ export default [ toggleSource: key, dataPlacement: 'top', dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required + required: $scope.$parent.configDataResolve[key].required, + ngDisabled: $rootScope.user_is_system_auditor }); } diff --git a/awx/ui/client/src/configuration/system-form/configuration-system.controller.js b/awx/ui/client/src/configuration/system-form/configuration-system.controller.js index 340e452870..3751e298a5 100644 --- a/awx/ui/client/src/configuration/system-form/configuration-system.controller.js +++ b/awx/ui/client/src/configuration/system-form/configuration-system.controller.js @@ -5,9 +5,10 @@ *************************************************/ export default [ - '$scope', '$state', 'AngularCodeMirror', 'ConfigurationSystemForm', 'ConfigurationService', 'ConfigurationUtils', 'GenerateForm', 'ParseTypeChange', + '$rootScope', '$scope', '$state', 'AngularCodeMirror', 'Authorization', 'ConfigurationSystemForm', 'ConfigurationService', + 'ConfigurationUtils', 'GenerateForm', function( - $scope, $state, AngularCodeMirror, ConfigurationSystemForm, ConfigurationService, ConfigurationUtils, GenerateForm, ParseTypeChange + $rootScope, $scope, $state, AngularCodeMirror, Authorization, ConfigurationSystemForm, ConfigurationService, ConfigurationUtils, GenerateForm ) { var systemVm = this; var generator = GenerateForm; @@ -18,6 +19,9 @@ export default [ addFieldInfo(form, key); }); + // Disable the save button for non-superusers + form.buttons.save.disabled = 'vm.updateProhibited'; + function addFieldInfo(form, key) { _.extend(form.fields[key], { awPopOver: $scope.$parent.configDataResolve[key].help_text, @@ -26,7 +30,8 @@ export default [ toggleSource: key, dataPlacement: 'top', dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required + required: $scope.$parent.configDataResolve[key].required, + ngDisabled: $rootScope.user_is_system_auditor }); } @@ -37,31 +42,6 @@ export default [ related: true }); - - $scope.$on('populated', function() { - - // var fld = 'LICENSE'; - // var readOnly = true; - // $scope.$parent[fld + 'codeMirror'] = AngularCodeMirror(readOnly); - // $scope.$parent[fld + 'codeMirror'].addModes($AnsibleConfig.variable_edit_modes); - // $scope.$parent[fld + 'codeMirror'].showTextArea({ - // scope: $scope.$parent, - // model: fld, - // element: "configuration_system_template_LICENSE", - // lineNumbers: true, - // mode: 'json', - // }); - - $scope.$parent.parseType = 'json'; - ParseTypeChange({ - scope: $scope.$parent, - variable: 'LICENSE', - parse_variable: 'parseType', - field_id: 'configuration_system_template_LICENSE', - readOnly: true - }); - }); - angular.extend(systemVm, { }); diff --git a/awx/ui/client/src/configuration/system-form/configuration-system.form.js b/awx/ui/client/src/configuration/system-form/configuration-system.form.js index 47a4ceac0b..159dd99ee1 100644 --- a/awx/ui/client/src/configuration/system-form/configuration-system.form.js +++ b/awx/ui/client/src/configuration/system-form/configuration-system.form.js @@ -27,12 +27,12 @@ export default ['i18n', function(i18n) { ORG_ADMINS_CAN_SEE_ALL_USERS: { type: 'toggleSwitch', }, - LICENSE: { - type: 'textarea', - rows: 6, - codeMirror: true, - class: 'Form-textAreaLabel Form-formGroup--fullWidth' - } + // LICENSE: { + // type: 'textarea', + // rows: 6, + // codeMirror: true, + // class: 'Form-textAreaLabel Form-formGroup--fullWidth' + // } }, buttons: { diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js b/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js index f9f8f4eaad..aff68d72dc 100644 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js +++ b/awx/ui/client/src/configuration/ui-form/configuration-ui.controller.js @@ -6,6 +6,7 @@ export default [ '$scope', + '$rootScope', '$state', '$timeout', 'ConfigurationUiForm', @@ -15,6 +16,7 @@ 'i18n', function( $scope, + $rootScope, $state, $timeout, ConfigurationUiForm, @@ -45,6 +47,9 @@ addFieldInfo(form, key); }); + // Disable the save button for non-superusers + form.buttons.save.disabled = 'vm.updateProhibited'; + function addFieldInfo(form, key) { _.extend(form.fields[key], { awPopOver: $scope.$parent.configDataResolve[key].help_text, @@ -53,7 +58,8 @@ toggleSource: key, dataPlacement: 'top', dataTitle: $scope.$parent.configDataResolve[key].label, - required: $scope.$parent.configDataResolve[key].required + required: $scope.$parent.configDataResolve[key].required, + ngDisabled: $rootScope.user_is_system_auditor }); } diff --git a/awx/ui/client/src/setup-menu/setup-menu.partial.html b/awx/ui/client/src/setup-menu/setup-menu.partial.html index 8281a68a29..7ec7631dc7 100644 --- a/awx/ui/client/src/setup-menu/setup-menu.partial.html +++ b/awx/ui/client/src/setup-menu/setup-menu.partial.html @@ -49,7 +49,7 @@ View and edit your license information.

- +

Configure Tower

Edit Tower's configuration. diff --git a/awx/ui/client/src/shared/branding/colors.less b/awx/ui/client/src/shared/branding/colors.less index 044ba75db7..cb8a4cc098 100644 --- a/awx/ui/client/src/shared/branding/colors.less +++ b/awx/ui/client/src/shared/branding/colors.less @@ -11,6 +11,7 @@ @info: #d9edf7; /* alert info background color */ @info-border: #bce8f1; /* alert info border color */ @info-color: #3a87ad; +@info-close: #ccdeed; @unreachable: #FF0000; @changed: #FF9900; // Ansible Changed @skipped: #2dbaba; // Ansible Skipped diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 5866a464ba..defdc6f5dc 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1733,15 +1733,26 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat if (btn !== 'reset') { //html += "ng-disabled=\"" + this.form.name + "_form.$pristine || " + this.form.name + "_form.$invalid"; - html += "ng-disabled=\"" + ngDisabled; - //html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : ""; - html += "\" "; + if (button.disabled && button.disable !== true) { + // Allow disabled to overrule ng-disabled. Used for permissions. + // Example: system auditor can view but not update. Form validity + // is no longer a concern but ng-disabled will update disabled + // status on render so we stop applying it here. + } else { + html += "ng-disabled=\"" + ngDisabled; + //html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : ""; + html += "\" "; + } + } else { //html += "ng-disabled=\"" + this.form.name + "_form.$pristine"; //html += (this.form.allowReadonly) ? " || " + this.form.name + "ReadOnly == true" : ""; //html += "\" "; } } + if (button.disabled && button.disable !== true) { + html += ` disabled="disabled" `; + } if(button.awToolTip) { html += " aw-tool-tip='" + button.awToolTip + "' data-placement='" + button.dataPlacement + "' data-tip-watch='" + button.dataTipWatch + "'"; }