mirror of
https://github.com/ansible/awx.git
synced 2026-03-23 03:45:01 -02:30
Merge branch 'devel' of https://github.com/ansible/ansible-tower into wf_rbac_prompt
This commit is contained in:
12
Makefile
12
Makefile
@@ -298,12 +298,10 @@ requirements_tower_dev:
|
|||||||
# Install third-party requirements needed for running unittests in jenkins
|
# Install third-party requirements needed for running unittests in jenkins
|
||||||
requirements_jenkins:
|
requirements_jenkins:
|
||||||
if [ "$(VENV_BASE)" ]; then \
|
if [ "$(VENV_BASE)" ]; then \
|
||||||
. $(VENV_BASE)/tower/bin/activate; \
|
. $(VENV_BASE)/tower/bin/activate && pip install -Ir requirements/requirements_jenkins.txt; \
|
||||||
$(VENV_BASE)/tower/bin/pip install -Ir requirements/requirements_jenkins.txt; \
|
|
||||||
else \
|
else \
|
||||||
pip install -Ir requirements/requirements_jenkins.txt; \
|
pip install -Ir requirements/requirements_jenkins.txt; \
|
||||||
fi && \
|
fi
|
||||||
$(NPM_BIN) install csslint
|
|
||||||
|
|
||||||
requirements: requirements_ansible requirements_tower
|
requirements: requirements_ansible requirements_tower
|
||||||
|
|
||||||
@@ -317,8 +315,8 @@ develop:
|
|||||||
pip uninstall -y awx; \
|
pip uninstall -y awx; \
|
||||||
$(PYTHON) setup.py develop; \
|
$(PYTHON) setup.py develop; \
|
||||||
else \
|
else \
|
||||||
sudo pip uninstall -y awx; \
|
pip uninstall -y awx; \
|
||||||
sudo $(PYTHON) setup.py develop; \
|
$(PYTHON) setup.py develop; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
version_file:
|
version_file:
|
||||||
@@ -448,7 +446,7 @@ pylint: reports
|
|||||||
|
|
||||||
check: flake8 pep8 # pyflakes pylint
|
check: flake8 pep8 # pyflakes pylint
|
||||||
|
|
||||||
TEST_DIRS=awx/main/tests
|
TEST_DIRS ?= awx/main/tests
|
||||||
# Run all API unit tests.
|
# Run all API unit tests.
|
||||||
test:
|
test:
|
||||||
@if [ "$(VENV_BASE)" ]; then \
|
@if [ "$(VENV_BASE)" ]; then \
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
import '../support/node';
|
|
||||||
|
|
||||||
import adhocModule from 'inventories/manage/adhoc/main';
|
|
||||||
import RestStub from '../support/rest-stub';
|
|
||||||
|
|
||||||
describe("adhoc.controller", function() {
|
|
||||||
var $scope, $rootScope, $location, $stateParams, $stateExtender,
|
|
||||||
CheckPasswords, PromptForPasswords, CreateLaunchDialog, AdhocForm,
|
|
||||||
GenerateForm, Rest, ProcessErrors, ClearScope, GetBasePath, GetChoices,
|
|
||||||
KindChange, LookUpInit, CredentialList, Empty, Wait;
|
|
||||||
|
|
||||||
var $controller, ctrl, generateFormCallback, waitCallback, locationCallback,
|
|
||||||
getBasePath, processErrorsCallback, restCallback, stateExtenderCallback;
|
|
||||||
|
|
||||||
beforeEach("instantiate the adhoc module", function() {
|
|
||||||
angular.mock.module(adhocModule.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
before("create spies", function() {
|
|
||||||
getBasePath = function(path) {
|
|
||||||
return '/' + path + '/';
|
|
||||||
};
|
|
||||||
generateFormCallback = {
|
|
||||||
inject: angular.noop
|
|
||||||
};
|
|
||||||
waitCallback = sinon.spy();
|
|
||||||
locationCallback = {
|
|
||||||
path: sinon.spy()
|
|
||||||
};
|
|
||||||
processErrorsCallback = sinon.spy();
|
|
||||||
restCallback = new RestStub();
|
|
||||||
stateExtenderCallback = {
|
|
||||||
addState: angular.noop
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
beforeEach("mock dependencies", angular.mock.module(['$provide', function(_provide_) {
|
|
||||||
var $provide = _provide_;
|
|
||||||
|
|
||||||
$provide.value('$location', locationCallback);
|
|
||||||
$provide.value('CheckPasswords', angular.noop);
|
|
||||||
$provide.value('PromptForPasswords', angular.noop);
|
|
||||||
$provide.value('CreateLaunchDialog', angular.noop);
|
|
||||||
$provide.value('AdhocForm', angular.noop);
|
|
||||||
$provide.value('GenerateForm', generateFormCallback);
|
|
||||||
$provide.value('Rest', restCallback);
|
|
||||||
$provide.value('ProcessErrors', processErrorsCallback);
|
|
||||||
$provide.value('ClearScope', angular.noop);
|
|
||||||
$provide.value('GetBasePath', getBasePath);
|
|
||||||
$provide.value('GetChoices', angular.noop);
|
|
||||||
$provide.value('KindChange', angular.noop);
|
|
||||||
$provide.value('LookUpInit', angular.noop);
|
|
||||||
$provide.value('CredentialList', angular.noop);
|
|
||||||
$provide.value('Empty', angular.noop);
|
|
||||||
$provide.value('Wait', waitCallback);
|
|
||||||
$provide.value('$stateExtender', stateExtenderCallback);
|
|
||||||
$provide.value('$stateParams', angular.noop);
|
|
||||||
$provide.value('$state', angular.noop);
|
|
||||||
}]));
|
|
||||||
|
|
||||||
beforeEach("put the controller in scope", inject(function($rootScope, $controller) {
|
|
||||||
var scope = $rootScope.$new();
|
|
||||||
ctrl = $controller('adhocController', {$scope: scope});
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach("put $q in scope", window.inject(['$q', function($q) {
|
|
||||||
restCallback.$q = $q;
|
|
||||||
}]));
|
|
||||||
/*
|
|
||||||
describe("setAvailableUrls", function() {
|
|
||||||
it('should only have the specified urls ' +
|
|
||||||
'available for adhoc commands', function() {
|
|
||||||
var urls = ctrl.privateFn.setAvailableUrls();
|
|
||||||
expect(urls).to.have.keys('adhocUrl', 'inventoryUrl',
|
|
||||||
'machineCredentialUrl');
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i in urls) {
|
|
||||||
if (urls.hasOwnProperty(i)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(count).to.equal(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("setFieldDefaults", function() {
|
|
||||||
it('should set the select form field defaults' +
|
|
||||||
'based on user settings', function() {
|
|
||||||
var verbosity_options = [
|
|
||||||
{label: "0 (Foo)", value: 0, name: "0 (Foo)",
|
|
||||||
isDefault: false},
|
|
||||||
{label: "1 (Bar)", value: 1, name: "1 (Bar)",
|
|
||||||
isDefault: true},
|
|
||||||
],
|
|
||||||
forks_field = {};
|
|
||||||
|
|
||||||
forks_field.default = 3;
|
|
||||||
|
|
||||||
$scope.$apply(function() {
|
|
||||||
ctrl.privateFn.setFieldDefaults(verbosity_options,
|
|
||||||
forks_field.default);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect($scope.forks).to.equal(forks_field.default);
|
|
||||||
expect($scope.verbosity.value).to.equal(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("setLoadingStartStop", function() {
|
|
||||||
it('should start the controller working state when the form is ' +
|
|
||||||
'loading', function() {
|
|
||||||
waitCallback.reset();
|
|
||||||
ctrl.privateFn.setLoadingStartStop();
|
|
||||||
expect(waitCallback).to.have.been.calledWith("start");
|
|
||||||
});
|
|
||||||
it('should stop the indicator after all REST calls in the form load have ' +
|
|
||||||
'completed', function() {
|
|
||||||
var forks_field = {},
|
|
||||||
adhoc_verbosity_options = {};
|
|
||||||
forks_field.default = "1";
|
|
||||||
$scope.$apply(function() {
|
|
||||||
$scope.forks_field = forks_field;
|
|
||||||
$scope.adhoc_verbosity_options = adhoc_verbosity_options;
|
|
||||||
});
|
|
||||||
waitCallback.reset();
|
|
||||||
$scope.$emit('adhocFormReady');
|
|
||||||
$scope.$emit('adhocFormReady');
|
|
||||||
expect(waitCallback).to.have.been.calledWith("stop");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("instantiateArgumentHelp", function() {
|
|
||||||
it("should initially provide a canned argument help response", function() {
|
|
||||||
expect($scope.argsPopOver).to.equal('<p>These arguments are used ' +
|
|
||||||
'with the specified module.</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should change the help response when the module changes", function() {
|
|
||||||
$scope.$apply(function () {
|
|
||||||
$scope.module_name = {value: 'foo'};
|
|
||||||
});
|
|
||||||
expect($scope.argsPopOver).to.equal('<p>These arguments are used ' +
|
|
||||||
'with the specified module. You can find information about ' +
|
|
||||||
'the foo module <a ' +
|
|
||||||
'id=\"adhoc_module_arguments_docs_link_for_module_foo\" ' +
|
|
||||||
'href=\"http://docs.ansible.com/foo_module.html\" ' +
|
|
||||||
'target=\"_blank\">here</a>.</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should change the help response when the module changes again", function() {
|
|
||||||
$scope.$apply(function () {
|
|
||||||
$scope.module_name = {value: 'bar'};
|
|
||||||
});
|
|
||||||
expect($scope.argsPopOver).to.equal('<p>These arguments are used ' +
|
|
||||||
'with the specified module. You can find information about ' +
|
|
||||||
'the bar module <a ' +
|
|
||||||
'id=\"adhoc_module_arguments_docs_link_for_module_bar\" ' +
|
|
||||||
'href=\"http://docs.ansible.com/bar_module.html\" ' +
|
|
||||||
'target=\"_blank\">here</a>.</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should change the help response back to the canned response " +
|
|
||||||
"when no module is selected", function() {
|
|
||||||
$scope.$apply(function () {
|
|
||||||
$scope.module_name = null;
|
|
||||||
});
|
|
||||||
expect($scope.argsPopOver).to.equal('<p>These arguments are used ' +
|
|
||||||
'with the specified module.</p>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("instantiateHostPatterns", function() {
|
|
||||||
it("should initialize the limit object based on the provided host " +
|
|
||||||
"pattern", function() {
|
|
||||||
ctrl.privateFn.instantiateHostPatterns("foo:bar");
|
|
||||||
expect($scope.limit).to.equal("foo:bar");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the providedHostPatterns variable to the provided host " +
|
|
||||||
"pattern so it is accesible on form reset", function() {
|
|
||||||
ctrl.privateFn.instantiateHostPatterns("foo:bar");
|
|
||||||
expect($scope.providedHostPatterns).to.equal("foo:bar");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should remove the hostPattern from rootScope after it has been " +
|
|
||||||
"utilized", function() {
|
|
||||||
$rootScope.hostPatterns = "foo";
|
|
||||||
expect($rootScope.hostPatterns).to.exist;
|
|
||||||
ctrl.privateFn.instantiateHostPatterns("foo");
|
|
||||||
expect($rootScope.hostPatterns).to.not.exist;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
@@ -235,6 +235,13 @@ class ListAPIView(generics.ListAPIView, GenericAPIView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.request.user.get_queryset(self.model)
|
return self.request.user.get_queryset(self.model)
|
||||||
|
|
||||||
|
def paginate_queryset(self, queryset):
|
||||||
|
page = super(ListAPIView, self).paginate_queryset(queryset)
|
||||||
|
# Queries RBAC info & stores into list objects
|
||||||
|
if hasattr(self, 'capabilities_prefetch') and page is not None:
|
||||||
|
cache_list_capabilities(page, self.capabilities_prefetch, self.model, self.request.user)
|
||||||
|
return page
|
||||||
|
|
||||||
def get_description_context(self):
|
def get_description_context(self):
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
if 'username' in opts.get_all_field_names():
|
if 'username' in opts.get_all_field_names():
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ class ModelAccessPermission(permissions.BasePermission):
|
|||||||
if not check_user_access(request.user, view.parent_model, 'read',
|
if not check_user_access(request.user, view.parent_model, 'read',
|
||||||
parent_obj):
|
parent_obj):
|
||||||
return False
|
return False
|
||||||
|
if hasattr(view, 'parent_key'):
|
||||||
|
if not check_user_access(request.user, view.model, 'add', {view.parent_key: parent_obj.pk}):
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
elif getattr(view, 'is_job_start', False):
|
elif getattr(view, 'is_job_start', False):
|
||||||
if not obj:
|
if not obj:
|
||||||
@@ -206,6 +209,8 @@ class ProjectUpdatePermission(ModelAccessPermission):
|
|||||||
|
|
||||||
class UserPermission(ModelAccessPermission):
|
class UserPermission(ModelAccessPermission):
|
||||||
def check_post_permissions(self, request, view, obj=None):
|
def check_post_permissions(self, request, view, obj=None):
|
||||||
if request.user.is_superuser:
|
if not request.data:
|
||||||
|
return request.user.admin_of_organizations.exists()
|
||||||
|
elif request.user.is_superuser:
|
||||||
return True
|
return True
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from polymorphic import PolymorphicModel
|
|||||||
# AWX
|
# AWX
|
||||||
from awx.main.constants import SCHEDULEABLE_PROVIDERS
|
from awx.main.constants import SCHEDULEABLE_PROVIDERS
|
||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
|
from awx.main.access import get_user_capabilities
|
||||||
from awx.main.fields import ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField
|
||||||
from awx.main.utils import get_type_for_model, get_model_for_type, build_url, timestamp_apiformat, camelcase_to_underscore, getattrd
|
from awx.main.utils import get_type_for_model, get_model_for_type, build_url, timestamp_apiformat, camelcase_to_underscore, getattrd
|
||||||
from awx.main.conf import tower_settings
|
from awx.main.conf import tower_settings
|
||||||
@@ -345,6 +346,19 @@ class BaseSerializer(serializers.ModelSerializer):
|
|||||||
}
|
}
|
||||||
if len(roles) > 0:
|
if len(roles) > 0:
|
||||||
summary_fields['object_roles'] = roles
|
summary_fields['object_roles'] = roles
|
||||||
|
|
||||||
|
# Advance display of RBAC capabilities
|
||||||
|
if hasattr(self, 'show_capabilities'):
|
||||||
|
view = self.context.get('view', None)
|
||||||
|
parent_obj = None
|
||||||
|
if view and hasattr(view, 'parent_model'):
|
||||||
|
parent_obj = view.get_parent_object()
|
||||||
|
if view and view.request and view.request.user:
|
||||||
|
user_capabilities = get_user_capabilities(
|
||||||
|
view.request.user, obj, method_list=self.show_capabilities, parent_obj=parent_obj)
|
||||||
|
if user_capabilities:
|
||||||
|
summary_fields['user_capabilities'] = user_capabilities
|
||||||
|
|
||||||
return summary_fields
|
return summary_fields
|
||||||
|
|
||||||
def get_created(self, obj):
|
def get_created(self, obj):
|
||||||
@@ -553,6 +567,7 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class UnifiedJobSerializer(BaseSerializer):
|
class UnifiedJobSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['start', 'delete']
|
||||||
|
|
||||||
result_stdout = serializers.SerializerMethodField()
|
result_stdout = serializers.SerializerMethodField()
|
||||||
|
|
||||||
@@ -697,11 +712,12 @@ class UserSerializer(BaseSerializer):
|
|||||||
ldap_dn = serializers.CharField(source='profile.ldap_dn', read_only=True)
|
ldap_dn = serializers.CharField(source='profile.ldap_dn', read_only=True)
|
||||||
external_account = serializers.SerializerMethodField(help_text='Set if the account is managed by an external service')
|
external_account = serializers.SerializerMethodField(help_text='Set if the account is managed by an external service')
|
||||||
is_system_auditor = serializers.BooleanField(default=False)
|
is_system_auditor = serializers.BooleanField(default=False)
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ('*', '-name', '-description', '-modified',
|
fields = ('*', '-name', '-description', '-modified',
|
||||||
'-summary_fields', 'username', 'first_name', 'last_name',
|
'username', 'first_name', 'last_name',
|
||||||
'email', 'is_superuser', 'is_system_auditor', 'password', 'ldap_dn', 'external_account')
|
'email', 'is_superuser', 'is_system_auditor', 'password', 'ldap_dn', 'external_account')
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
@@ -822,6 +838,7 @@ class UserSerializer(BaseSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class OrganizationSerializer(BaseSerializer):
|
class OrganizationSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Organization
|
model = Organization
|
||||||
@@ -906,6 +923,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
|||||||
status = serializers.ChoiceField(choices=Project.PROJECT_STATUS_CHOICES, read_only=True)
|
status = serializers.ChoiceField(choices=Project.PROJECT_STATUS_CHOICES, read_only=True)
|
||||||
last_update_failed = serializers.BooleanField(read_only=True)
|
last_update_failed = serializers.BooleanField(read_only=True)
|
||||||
last_updated = serializers.DateTimeField(read_only=True)
|
last_updated = serializers.DateTimeField(read_only=True)
|
||||||
|
show_capabilities = ['start', 'schedule', 'edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Project
|
model = Project
|
||||||
@@ -1014,6 +1032,7 @@ class BaseSerializerWithVariables(BaseSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class InventorySerializer(BaseSerializerWithVariables):
|
class InventorySerializer(BaseSerializerWithVariables):
|
||||||
|
show_capabilities = ['edit', 'delete', 'adhoc']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Inventory
|
model = Inventory
|
||||||
@@ -1064,12 +1083,14 @@ class InventoryDetailSerializer(InventorySerializer):
|
|||||||
|
|
||||||
|
|
||||||
class InventoryScriptSerializer(InventorySerializer):
|
class InventoryScriptSerializer(InventorySerializer):
|
||||||
|
show_capabilities = ['copy', 'edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = ()
|
fields = ()
|
||||||
|
|
||||||
|
|
||||||
class HostSerializer(BaseSerializerWithVariables):
|
class HostSerializer(BaseSerializerWithVariables):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Host
|
model = Host
|
||||||
@@ -1180,6 +1201,7 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
|
|
||||||
|
|
||||||
class GroupSerializer(BaseSerializerWithVariables):
|
class GroupSerializer(BaseSerializerWithVariables):
|
||||||
|
show_capabilities = ['start', 'copy', 'schedule', 'edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
@@ -1284,6 +1306,7 @@ class GroupVariableDataSerializer(BaseVariableDataSerializer):
|
|||||||
class CustomInventoryScriptSerializer(BaseSerializer):
|
class CustomInventoryScriptSerializer(BaseSerializer):
|
||||||
|
|
||||||
script = serializers.CharField(trim_whitespace=False)
|
script = serializers.CharField(trim_whitespace=False)
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomInventoryScript
|
model = CustomInventoryScript
|
||||||
@@ -1454,6 +1477,7 @@ class InventoryUpdateCancelSerializer(InventoryUpdateSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class TeamSerializer(BaseSerializer):
|
class TeamSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Team
|
model = Team
|
||||||
@@ -1522,8 +1546,12 @@ class RoleSerializer(BaseSerializer):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class RoleSerializerWithParentAccess(RoleSerializer):
|
||||||
|
show_capabilities = ['unattach']
|
||||||
|
|
||||||
|
|
||||||
class ResourceAccessListElementSerializer(UserSerializer):
|
class ResourceAccessListElementSerializer(UserSerializer):
|
||||||
|
show_capabilities = [] # Clear fields from UserSerializer parent class
|
||||||
|
|
||||||
def to_representation(self, user):
|
def to_representation(self, user):
|
||||||
'''
|
'''
|
||||||
@@ -1539,18 +1567,25 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
|||||||
ret = super(ResourceAccessListElementSerializer, self).to_representation(user)
|
ret = super(ResourceAccessListElementSerializer, self).to_representation(user)
|
||||||
object_id = self.context['view'].object_id
|
object_id = self.context['view'].object_id
|
||||||
obj = self.context['view'].resource_model.objects.get(pk=object_id)
|
obj = self.context['view'].resource_model.objects.get(pk=object_id)
|
||||||
|
if self.context['view'].request is not None:
|
||||||
|
requesting_user = self.context['view'].request.user
|
||||||
|
else:
|
||||||
|
requesting_user = None
|
||||||
|
|
||||||
if 'summary_fields' not in ret:
|
if 'summary_fields' not in ret:
|
||||||
ret['summary_fields'] = {}
|
ret['summary_fields'] = {}
|
||||||
|
|
||||||
def format_role_perm(role):
|
def format_role_perm(role):
|
||||||
role_dict = { 'id': role.id, 'name': role.name, 'description': role.description}
|
role_dict = { 'id': role.id, 'name': role.name, 'description': role.description}
|
||||||
try:
|
if role.content_type is not None:
|
||||||
role_dict['resource_name'] = role.content_object.name
|
role_dict['resource_name'] = role.content_object.name
|
||||||
role_dict['resource_type'] = role.content_type.name
|
role_dict['resource_type'] = role.content_type.name
|
||||||
role_dict['related'] = reverse_gfk(role.content_object)
|
role_dict['related'] = reverse_gfk(role.content_object)
|
||||||
except:
|
role_dict['user_capabilities'] = {'unattach': requesting_user.can_access(
|
||||||
pass
|
Role, 'unattach', role, user, 'members', data={}, skip_sub_obj_read_check=False)}
|
||||||
|
else:
|
||||||
|
# Singleton roles should not be managed from this view, as per copy/edit rework spec
|
||||||
|
role_dict['user_capabilities'] = {'unattach': False}
|
||||||
return { 'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, role)}
|
return { 'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, role)}
|
||||||
|
|
||||||
def format_team_role_perm(team_role, permissive_role_ids):
|
def format_team_role_perm(team_role, permissive_role_ids):
|
||||||
@@ -1563,20 +1598,21 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
|||||||
'team_id': team_role.object_id,
|
'team_id': team_role.object_id,
|
||||||
'team_name': team_role.content_object.name
|
'team_name': team_role.content_object.name
|
||||||
}
|
}
|
||||||
try:
|
if role.content_type is not None:
|
||||||
role_dict['resource_name'] = role.content_object.name
|
role_dict['resource_name'] = role.content_object.name
|
||||||
role_dict['resource_type'] = role.content_type.name
|
role_dict['resource_type'] = role.content_type.name
|
||||||
role_dict['related'] = reverse_gfk(role.content_object)
|
role_dict['related'] = reverse_gfk(role.content_object)
|
||||||
except:
|
role_dict['user_capabilities'] = {'unattach': requesting_user.can_access(
|
||||||
pass
|
Role, 'unattach', role, team_role, 'parents', data={}, skip_sub_obj_read_check=False)}
|
||||||
|
else:
|
||||||
|
# Singleton roles should not be managed from this view, as per copy/edit rework spec
|
||||||
|
role_dict['user_capabilities'] = {'unattach': False}
|
||||||
ret.append({ 'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, team_role)})
|
ret.append({ 'role': role_dict, 'descendant_roles': get_roles_on_resource(obj, team_role)})
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
team_content_type = ContentType.objects.get_for_model(Team)
|
team_content_type = ContentType.objects.get_for_model(Team)
|
||||||
content_type = ContentType.objects.get_for_model(obj)
|
content_type = ContentType.objects.get_for_model(obj)
|
||||||
|
|
||||||
|
|
||||||
content_type = ContentType.objects.get_for_model(obj)
|
|
||||||
direct_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('id', flat=True)
|
direct_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('id', flat=True)
|
||||||
all_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('ancestors__id', flat=True)
|
all_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('ancestors__id', flat=True)
|
||||||
|
|
||||||
@@ -1621,6 +1657,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class CredentialSerializer(BaseSerializer):
|
class CredentialSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Credential
|
model = Credential
|
||||||
@@ -1825,6 +1862,7 @@ class JobOptionsSerializer(BaseSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
||||||
|
show_capabilities = ['start', 'schedule', 'copy', 'edit', 'delete']
|
||||||
|
|
||||||
status = serializers.ChoiceField(choices=JobTemplate.JOB_TEMPLATE_STATUS_CHOICES, read_only=True, required=False)
|
status = serializers.ChoiceField(choices=JobTemplate.JOB_TEMPLATE_STATUS_CHOICES, read_only=True, required=False)
|
||||||
|
|
||||||
@@ -1860,21 +1898,6 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
|||||||
d = super(JobTemplateSerializer, self).get_summary_fields(obj)
|
d = super(JobTemplateSerializer, self).get_summary_fields(obj)
|
||||||
if obj.survey_spec is not None and ('name' in obj.survey_spec and 'description' in obj.survey_spec):
|
if obj.survey_spec is not None and ('name' in obj.survey_spec and 'description' in obj.survey_spec):
|
||||||
d['survey'] = dict(title=obj.survey_spec['name'], description=obj.survey_spec['description'])
|
d['survey'] = dict(title=obj.survey_spec['name'], description=obj.survey_spec['description'])
|
||||||
request = self.context.get('request', None)
|
|
||||||
|
|
||||||
# Check for conditions that would create a validation error if coppied
|
|
||||||
validation_errors, resources_needed_to_start = obj.resource_validation_data()
|
|
||||||
|
|
||||||
if request is None or request.user is None:
|
|
||||||
d['can_copy'] = False
|
|
||||||
d['can_edit'] = False
|
|
||||||
elif request.user.is_superuser:
|
|
||||||
d['can_copy'] = not validation_errors
|
|
||||||
d['can_edit'] = True
|
|
||||||
else:
|
|
||||||
d['can_copy'] = (not validation_errors) and request.user.can_access(JobTemplate, 'add', {"reference_obj": obj})
|
|
||||||
d['can_edit'] = request.user.can_access(JobTemplate, 'change', obj, {})
|
|
||||||
|
|
||||||
d['recent_jobs'] = self._recent_jobs(obj)
|
d['recent_jobs'] = self._recent_jobs(obj)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -2561,6 +2584,7 @@ class JobLaunchSerializer(BaseSerializer):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
class NotificationTemplateSerializer(BaseSerializer):
|
class NotificationTemplateSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = NotificationTemplate
|
model = NotificationTemplate
|
||||||
@@ -2674,6 +2698,7 @@ class LabelSerializer(BaseSerializer):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
class ScheduleSerializer(BaseSerializer):
|
class ScheduleSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Schedule
|
model = Schedule
|
||||||
|
|||||||
@@ -854,7 +854,7 @@ class TeamUsersList(BaseUsersList):
|
|||||||
class TeamRolesList(SubListCreateAttachDetachAPIView):
|
class TeamRolesList(SubListCreateAttachDetachAPIView):
|
||||||
|
|
||||||
model = Role
|
model = Role
|
||||||
serializer_class = RoleSerializer
|
serializer_class = RoleSerializerWithParentAccess
|
||||||
metadata_class = RoleMetadata
|
metadata_class = RoleMetadata
|
||||||
parent_model = Team
|
parent_model = Team
|
||||||
relationship='member_role.children'
|
relationship='member_role.children'
|
||||||
@@ -953,6 +953,7 @@ class ProjectList(ListCreateAPIView):
|
|||||||
|
|
||||||
model = Project
|
model = Project
|
||||||
serializer_class = ProjectSerializer
|
serializer_class = ProjectSerializer
|
||||||
|
capabilities_prefetch = ['admin', 'update']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
projects_qs = Project.accessible_objects(self.request.user, 'read_role')
|
projects_qs = Project.accessible_objects(self.request.user, 'read_role')
|
||||||
@@ -1151,6 +1152,7 @@ class UserList(ListCreateAPIView):
|
|||||||
|
|
||||||
model = User
|
model = User
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
capabilities_prefetch = ['admin']
|
||||||
permission_classes = (UserPermission,)
|
permission_classes = (UserPermission,)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
@@ -1191,7 +1193,7 @@ class UserTeamsList(ListAPIView):
|
|||||||
class UserRolesList(SubListCreateAttachDetachAPIView):
|
class UserRolesList(SubListCreateAttachDetachAPIView):
|
||||||
|
|
||||||
model = Role
|
model = Role
|
||||||
serializer_class = RoleSerializer
|
serializer_class = RoleSerializerWithParentAccess
|
||||||
metadata_class = RoleMetadata
|
metadata_class = RoleMetadata
|
||||||
parent_model = User
|
parent_model = User
|
||||||
relationship='roles'
|
relationship='roles'
|
||||||
@@ -1511,6 +1513,7 @@ class InventoryList(ListCreateAPIView):
|
|||||||
|
|
||||||
model = Inventory
|
model = Inventory
|
||||||
serializer_class = InventorySerializer
|
serializer_class = InventorySerializer
|
||||||
|
capabilities_prefetch = ['admin', 'adhoc']
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = Inventory.accessible_objects(self.request.user, 'read_role')
|
qs = Inventory.accessible_objects(self.request.user, 'read_role')
|
||||||
@@ -1742,6 +1745,7 @@ class GroupList(ListCreateAPIView):
|
|||||||
|
|
||||||
model = Group
|
model = Group
|
||||||
serializer_class = GroupSerializer
|
serializer_class = GroupSerializer
|
||||||
|
capabilities_prefetch = ['inventory.admin', 'inventory.adhoc', 'inventory.update']
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Useful when you have a self-refering ManyToManyRelationship.
|
Useful when you have a self-refering ManyToManyRelationship.
|
||||||
@@ -2210,6 +2214,10 @@ class JobTemplateList(ListCreateAPIView):
|
|||||||
model = JobTemplate
|
model = JobTemplate
|
||||||
serializer_class = JobTemplateSerializer
|
serializer_class = JobTemplateSerializer
|
||||||
always_allow_superuser = False
|
always_allow_superuser = False
|
||||||
|
capabilities_prefetch = [
|
||||||
|
'admin', 'execute',
|
||||||
|
{'copy': ['project.use', 'inventory.use', 'credential.use', 'cloud_credential.use', 'network_credential.use']}
|
||||||
|
]
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
ret = super(JobTemplateList, self).post(request, *args, **kwargs)
|
ret = super(JobTemplateList, self).post(request, *args, **kwargs)
|
||||||
@@ -3680,6 +3688,7 @@ class NotificationTemplateTest(GenericAPIView):
|
|||||||
model = NotificationTemplate
|
model = NotificationTemplate
|
||||||
serializer_class = EmptySerializer
|
serializer_class = EmptySerializer
|
||||||
new_in_300 = True
|
new_in_300 = True
|
||||||
|
is_job_start = True
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
|
|||||||
@@ -116,6 +116,18 @@ def check_user_access(user, model_class, action, *args, **kwargs):
|
|||||||
return result
|
return result
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_user_capabilities(user, instance, **kwargs):
|
||||||
|
'''
|
||||||
|
Returns a dictionary of capabilities the user has on the particular
|
||||||
|
instance. *NOTE* This is not a direct mapping of can_* methods into this
|
||||||
|
dictionary, it is intended to munge some queries in a way that is
|
||||||
|
convenient for the user interface to consume and hide or show various
|
||||||
|
actions in the interface.
|
||||||
|
'''
|
||||||
|
for access_class in access_registry.get(type(instance), []):
|
||||||
|
return access_class(user).get_user_capabilities(instance, **kwargs)
|
||||||
|
return None
|
||||||
|
|
||||||
def check_superuser(func):
|
def check_superuser(func):
|
||||||
'''
|
'''
|
||||||
check_superuser is a decorator that provides a simple short circuit
|
check_superuser is a decorator that provides a simple short circuit
|
||||||
@@ -207,6 +219,78 @@ class BaseAccess(object):
|
|||||||
elif "features" not in validation_info:
|
elif "features" not in validation_info:
|
||||||
raise LicenseForbids("Features not found in active license.")
|
raise LicenseForbids("Features not found in active license.")
|
||||||
|
|
||||||
|
def get_user_capabilities(self, obj, method_list=[], parent_obj=None):
|
||||||
|
if obj is None:
|
||||||
|
return {}
|
||||||
|
user_capabilities = {}
|
||||||
|
|
||||||
|
# Custom ordering to loop through methods so we can reuse earlier calcs
|
||||||
|
for display_method in ['edit', 'delete', 'start', 'schedule', 'copy', 'adhoc', 'unattach']:
|
||||||
|
if display_method not in method_list:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Validation consistency checks
|
||||||
|
if display_method == 'copy' and isinstance(obj, JobTemplate):
|
||||||
|
validation_errors, resources_needed_to_start = obj.resource_validation_data()
|
||||||
|
if validation_errors:
|
||||||
|
user_capabilities[display_method] = False
|
||||||
|
continue
|
||||||
|
elif display_method == 'start' and isinstance(obj, Group):
|
||||||
|
if obj.inventory_source and not obj.inventory_source._can_update():
|
||||||
|
user_capabilities[display_method] = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Grab the answer from the cache, if available
|
||||||
|
if hasattr(obj, 'capabilities_cache') and display_method in obj.capabilities_cache:
|
||||||
|
user_capabilities[display_method] = obj.capabilities_cache[display_method]
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Aliases for going form UI language to API language
|
||||||
|
if display_method == 'edit':
|
||||||
|
method = 'change'
|
||||||
|
elif display_method == 'copy':
|
||||||
|
method = 'add'
|
||||||
|
elif display_method == 'adhoc':
|
||||||
|
method = 'run_ad_hoc_commands'
|
||||||
|
else:
|
||||||
|
method = display_method
|
||||||
|
|
||||||
|
# Shortcuts in certain cases by deferring to earlier property
|
||||||
|
if display_method == 'schedule':
|
||||||
|
user_capabilities['schedule'] = user_capabilities['edit']
|
||||||
|
continue
|
||||||
|
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob)):
|
||||||
|
user_capabilities['delete'] = user_capabilities['edit']
|
||||||
|
continue
|
||||||
|
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
|
||||||
|
user_capabilities['copy'] = user_capabilities['edit']
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Preprocessing before the access method is called
|
||||||
|
data = {}
|
||||||
|
if method == 'add':
|
||||||
|
if isinstance(obj, JobTemplate):
|
||||||
|
data['reference_obj'] = obj
|
||||||
|
|
||||||
|
# Compute permission
|
||||||
|
access_method = getattr(self, "can_%s" % method)
|
||||||
|
if method in ['change']: # 3 args
|
||||||
|
user_capabilities[display_method] = access_method(obj, data)
|
||||||
|
elif method in ['delete', 'start', 'run_ad_hoc_commands']: # 2 args
|
||||||
|
user_capabilities[display_method] = access_method(obj)
|
||||||
|
elif method in ['add']: # 2 args with data
|
||||||
|
user_capabilities[display_method] = access_method(data)
|
||||||
|
elif method in ['attach', 'unattach']: # parent/sub-object call
|
||||||
|
if type(parent_obj) == Team:
|
||||||
|
relationship = 'parents'
|
||||||
|
parent_obj = parent_obj.member_role
|
||||||
|
else:
|
||||||
|
relationship = 'members'
|
||||||
|
user_capabilities[display_method] = access_method(
|
||||||
|
obj, parent_obj, relationship, skip_sub_obj_read_check=True, data=data)
|
||||||
|
|
||||||
|
return user_capabilities
|
||||||
|
|
||||||
|
|
||||||
class UserAccess(BaseAccess):
|
class UserAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
@@ -526,6 +610,12 @@ class GroupAccess(BaseAccess):
|
|||||||
"active_jobs": active_jobs})
|
"active_jobs": active_jobs})
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def can_start(self, obj):
|
||||||
|
# Used as another alias to inventory_source start access for user_capabilities
|
||||||
|
if obj and obj.inventory_source:
|
||||||
|
return self.user.can_access(InventorySource, 'start', obj.inventory_source)
|
||||||
|
return False
|
||||||
|
|
||||||
class InventorySourceAccess(BaseAccess):
|
class InventorySourceAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see inventory sources whenever I can see their group or inventory.
|
I can see inventory sources whenever I can see their group or inventory.
|
||||||
@@ -594,6 +684,13 @@ class InventoryUpdateAccess(BaseAccess):
|
|||||||
# Inventory cascade deletes to inventory update, descends from org admin
|
# Inventory cascade deletes to inventory update, descends from org admin
|
||||||
return self.user in obj.inventory_source.inventory.admin_role
|
return self.user in obj.inventory_source.inventory.admin_role
|
||||||
|
|
||||||
|
def can_start(self, obj):
|
||||||
|
# For relaunching
|
||||||
|
if obj and obj.inventory_source:
|
||||||
|
access = InventorySourceAccess(self.user)
|
||||||
|
return access.can_start(obj.inventory_source)
|
||||||
|
return False
|
||||||
|
|
||||||
@check_superuser
|
@check_superuser
|
||||||
def can_delete(self, obj):
|
def can_delete(self, obj):
|
||||||
return self.user in obj.inventory_source.inventory.admin_role
|
return self.user in obj.inventory_source.inventory.admin_role
|
||||||
@@ -815,6 +912,12 @@ class ProjectUpdateAccess(BaseAccess):
|
|||||||
# Project updates cascade delete with project, admin role descends from org admin
|
# Project updates cascade delete with project, admin role descends from org admin
|
||||||
return self.user in obj.project.admin_role
|
return self.user in obj.project.admin_role
|
||||||
|
|
||||||
|
def can_start(self, obj):
|
||||||
|
# for relaunching
|
||||||
|
if obj and obj.project:
|
||||||
|
return self.user in obj.project.update_role
|
||||||
|
return False
|
||||||
|
|
||||||
@check_superuser
|
@check_superuser
|
||||||
def can_delete(self, obj):
|
def can_delete(self, obj):
|
||||||
return obj and self.user in obj.project.admin_role
|
return obj and self.user in obj.project.admin_role
|
||||||
@@ -855,7 +958,9 @@ class JobTemplateAccess(BaseAccess):
|
|||||||
Users who are able to create deploy jobs can also run normal and check (dry run) jobs.
|
Users who are able to create deploy jobs can also run normal and check (dry run) jobs.
|
||||||
'''
|
'''
|
||||||
if not data: # So the browseable API will work
|
if not data: # So the browseable API will work
|
||||||
return True
|
return (
|
||||||
|
Project.accessible_objects(self.user, 'use_role').exists() or
|
||||||
|
Inventory.accessible_objects(self.user, 'use_role').exists())
|
||||||
|
|
||||||
# if reference_obj is provided, determine if it can be coppied
|
# if reference_obj is provided, determine if it can be coppied
|
||||||
reference_obj = data.pop('reference_obj', None)
|
reference_obj = data.pop('reference_obj', None)
|
||||||
@@ -1132,6 +1237,10 @@ class SystemJobAccess(BaseAccess):
|
|||||||
'''
|
'''
|
||||||
model = SystemJob
|
model = SystemJob
|
||||||
|
|
||||||
|
def can_start(self, obj):
|
||||||
|
return False # no relaunching of system jobs
|
||||||
|
|
||||||
|
# TODO:
|
||||||
class WorkflowJobTemplateNodeAccess(BaseAccess):
|
class WorkflowJobTemplateNodeAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see/use a WorkflowJobTemplateNode if I have read permission
|
I can see/use a WorkflowJobTemplateNode if I have read permission
|
||||||
@@ -1762,6 +1871,12 @@ class NotificationTemplateAccess(BaseAccess):
|
|||||||
def can_delete(self, obj):
|
def can_delete(self, obj):
|
||||||
return self.can_change(obj, None)
|
return self.can_change(obj, None)
|
||||||
|
|
||||||
|
@check_superuser
|
||||||
|
def can_start(self, obj):
|
||||||
|
if obj.organization is None:
|
||||||
|
return False
|
||||||
|
return self.user in obj.organization.admin_role
|
||||||
|
|
||||||
class NotificationAccess(BaseAccess):
|
class NotificationAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see/use a notification if I have permission to
|
I can see/use a notification if I have permission to
|
||||||
@@ -1970,8 +2085,13 @@ class RoleAccess(BaseAccess):
|
|||||||
|
|
||||||
@check_superuser
|
@check_superuser
|
||||||
def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False):
|
def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False):
|
||||||
if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents']:
|
if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents', 'parents']:
|
||||||
if not check_user_access(self.user, sub_obj.__class__, 'read', sub_obj):
|
# If we are unattaching a team Role, check the Team read access
|
||||||
|
if relationship == 'parents':
|
||||||
|
sub_obj_resource = sub_obj.content_object
|
||||||
|
else:
|
||||||
|
sub_obj_resource = sub_obj
|
||||||
|
if not check_user_access(self.user, sub_obj_resource.__class__, 'read', sub_obj_resource):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if isinstance(obj.content_object, ResourceMixin) and \
|
if isinstance(obj.content_object, ResourceMixin) and \
|
||||||
|
|||||||
@@ -47,3 +47,4 @@ class Command(BaseCommand):
|
|||||||
inventory=i,
|
inventory=i,
|
||||||
credential=c)
|
credential=c)
|
||||||
print('Default organization added.')
|
print('Default organization added.')
|
||||||
|
print('Demo Credential, Inventory, and Job Template added.')
|
||||||
|
|||||||
@@ -340,6 +340,10 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
|||||||
errors.append("'%s' value missing" % survey_element['variable'])
|
errors.append("'%s' value missing" % survey_element['variable'])
|
||||||
elif survey_element['type'] in ["textarea", "text", "password"]:
|
elif survey_element['type'] in ["textarea", "text", "password"]:
|
||||||
if survey_element['variable'] in data:
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) not in (str, unicode):
|
||||||
|
errors.append("Value %s for '%s' expected to be a string." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
continue
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and len(data[survey_element['variable']]) < int(survey_element['min']):
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and len(data[survey_element['variable']]) < int(survey_element['min']):
|
||||||
errors.append("'%s' value %s is too small (length is %s must be at least %s)." %
|
errors.append("'%s' value %s is too small (length is %s must be at least %s)." %
|
||||||
(survey_element['variable'], data[survey_element['variable']], len(data[survey_element['variable']]), survey_element['min']))
|
(survey_element['variable'], data[survey_element['variable']], len(data[survey_element['variable']]), survey_element['min']))
|
||||||
@@ -348,6 +352,10 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
|||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
elif survey_element['type'] == 'integer':
|
elif survey_element['type'] == 'integer':
|
||||||
if survey_element['variable'] in data:
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) != int:
|
||||||
|
errors.append("Value %s for '%s' expected to be an integer." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
continue
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and survey_element['variable'] in data and \
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and survey_element['variable'] in data and \
|
||||||
data[survey_element['variable']] < int(survey_element['min']):
|
data[survey_element['variable']] < int(survey_element['min']):
|
||||||
errors.append("'%s' value %s is too small (must be at least %s)." %
|
errors.append("'%s' value %s is too small (must be at least %s)." %
|
||||||
@@ -356,20 +364,18 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
|||||||
data[survey_element['variable']] > int(survey_element['max']):
|
data[survey_element['variable']] > int(survey_element['max']):
|
||||||
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
if type(data[survey_element['variable']]) != int:
|
|
||||||
errors.append("Value %s for '%s' expected to be an integer." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable']))
|
|
||||||
elif survey_element['type'] == 'float':
|
elif survey_element['type'] == 'float':
|
||||||
if survey_element['variable'] in data:
|
if survey_element['variable'] in data:
|
||||||
|
if type(data[survey_element['variable']]) not in (float, int):
|
||||||
|
errors.append("Value %s for '%s' expected to be a numeric type." % (data[survey_element['variable']],
|
||||||
|
survey_element['variable']))
|
||||||
|
continue
|
||||||
if 'min' in survey_element and survey_element['min'] not in ["", None] and data[survey_element['variable']] < float(survey_element['min']):
|
if 'min' in survey_element and survey_element['min'] not in ["", None] and data[survey_element['variable']] < float(survey_element['min']):
|
||||||
errors.append("'%s' value %s is too small (must be at least %s)." %
|
errors.append("'%s' value %s is too small (must be at least %s)." %
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
(survey_element['variable'], data[survey_element['variable']], survey_element['min']))
|
||||||
if 'max' in survey_element and survey_element['max'] not in ["", None] and data[survey_element['variable']] > float(survey_element['max']):
|
if 'max' in survey_element and survey_element['max'] not in ["", None] and data[survey_element['variable']] > float(survey_element['max']):
|
||||||
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
errors.append("'%s' value %s is too large (must be no more than %s)." %
|
||||||
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
(survey_element['variable'], data[survey_element['variable']], survey_element['max']))
|
||||||
if type(data[survey_element['variable']]) not in (float, int):
|
|
||||||
errors.append("Value %s for '%s' expected to be a numeric type." % (data[survey_element['variable']],
|
|
||||||
survey_element['variable']))
|
|
||||||
elif survey_element['type'] == 'multiselect':
|
elif survey_element['type'] == 'multiselect':
|
||||||
if survey_element['variable'] in data:
|
if survey_element['variable'] in data:
|
||||||
if type(data[survey_element['variable']]) != list:
|
if type(data[survey_element['variable']]) != list:
|
||||||
|
|||||||
@@ -177,7 +177,6 @@ class WorkflowJobNode(WorkflowNodeBase):
|
|||||||
# TODO: merge artifacts, add ancestor_artifacts to kwargs
|
# TODO: merge artifacts, add ancestor_artifacts to kwargs
|
||||||
if extra_vars:
|
if extra_vars:
|
||||||
data['extra_vars'] = extra_vars
|
data['extra_vars'] = extra_vars
|
||||||
print ' job KV data: ' + str(data)
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
class WorkflowJobOptions(BaseModel):
|
class WorkflowJobOptions(BaseModel):
|
||||||
|
|||||||
@@ -654,7 +654,8 @@ class BaseTask(Task):
|
|||||||
if status == 'canceled':
|
if status == 'canceled':
|
||||||
raise Exception("Task %s(pk:%s) was canceled (rc=%s)" % (str(self.model.__class__), str(pk), str(rc)))
|
raise Exception("Task %s(pk:%s) was canceled (rc=%s)" % (str(self.model.__class__), str(pk), str(rc)))
|
||||||
else:
|
else:
|
||||||
raise Exception("Task %s(pk:%s) encountered an error (rc=%s)" % (str(self.model.__class__), str(pk), str(rc)))
|
raise Exception("Task %s(pk:%s) encountered an error (rc=%s), please see task stdout for details." %
|
||||||
|
(str(self.model.__class__), str(pk), str(rc)))
|
||||||
if not hasattr(settings, 'CELERY_UNIT_TEST'):
|
if not hasattr(settings, 'CELERY_UNIT_TEST'):
|
||||||
self.signal_finished(pk)
|
self.signal_finished(pk)
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import mock
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.api.serializers import JobTemplateSerializer, JobLaunchSerializer
|
from awx.api.serializers import JobTemplateSerializer, JobLaunchSerializer
|
||||||
from awx.main.models.jobs import JobTemplate, Job
|
from awx.main.models.jobs import Job
|
||||||
from awx.main.models.projects import ProjectOptions
|
from awx.main.models.projects import ProjectOptions
|
||||||
from awx.main.migrations import _save_password_keys as save_password_keys
|
from awx.main.migrations import _save_password_keys as save_password_keys
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.test.client import RequestFactory
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
||||||
@@ -141,131 +140,7 @@ def test_job_template_role_user(post, organization_factory, job_template_factory
|
|||||||
response = post(url, dict(id=jt_objects.job_template.execute_role.pk), objects.superusers.admin)
|
response = post(url, dict(id=jt_objects.job_template.execute_role.pk), objects.superusers.admin)
|
||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
|
|
||||||
# Test protection against limited set of validation problems
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_bad_data_copy_edit(admin_user, project):
|
|
||||||
"""
|
|
||||||
If a required resource (inventory here) was deleted, copying not allowed
|
|
||||||
because doing so would caues a validation error
|
|
||||||
"""
|
|
||||||
|
|
||||||
jt_res = JobTemplate.objects.create(
|
|
||||||
job_type='run',
|
|
||||||
project=project,
|
|
||||||
inventory=None, ask_inventory_on_launch=False, # not allowed
|
|
||||||
credential=None, ask_credential_on_launch=True,
|
|
||||||
name='deploy-job-template'
|
|
||||||
)
|
|
||||||
serializer = JobTemplateSerializer(jt_res)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = admin_user
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_res)
|
|
||||||
assert not response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
# Tests for correspondence between view info and actual access
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_admin_copy_edit(jt_copy_edit, admin_user):
|
|
||||||
"Absent a validation error, system admins can do everything"
|
|
||||||
|
|
||||||
# Serializer can_copy/can_edit fields
|
|
||||||
serializer = JobTemplateSerializer(jt_copy_edit)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = admin_user
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_copy_edit)
|
|
||||||
assert response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_org_admin_copy_edit(jt_copy_edit, org_admin):
|
|
||||||
"Organization admins SHOULD be able to copy a JT firmly in their org"
|
|
||||||
|
|
||||||
# Serializer can_copy/can_edit fields
|
|
||||||
serializer = JobTemplateSerializer(jt_copy_edit)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = org_admin
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_copy_edit)
|
|
||||||
assert response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_org_admin_foreign_cred_no_copy_edit(jt_copy_edit, org_admin, machine_credential):
|
|
||||||
"""
|
|
||||||
Organization admins without access to the 3 related resources:
|
|
||||||
SHOULD NOT be able to copy JT
|
|
||||||
SHOULD be able to edit that job template, for nonsensitive changes
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Attach credential to JT that org admin can not use
|
|
||||||
jt_copy_edit.credential = machine_credential
|
|
||||||
jt_copy_edit.save()
|
|
||||||
|
|
||||||
# Serializer can_copy/can_edit fields
|
|
||||||
serializer = JobTemplateSerializer(jt_copy_edit)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = org_admin
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_copy_edit)
|
|
||||||
assert not response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_jt_admin_copy_edit(jt_copy_edit, rando):
|
|
||||||
"""
|
|
||||||
JT admins wihout access to associated resources SHOULD NOT be able to copy
|
|
||||||
SHOULD be able to make nonsensitive changes"""
|
|
||||||
|
|
||||||
# random user given JT admin access only
|
|
||||||
jt_copy_edit.admin_role.members.add(rando)
|
|
||||||
jt_copy_edit.save()
|
|
||||||
|
|
||||||
# Serializer can_copy/can_edit fields
|
|
||||||
serializer = JobTemplateSerializer(jt_copy_edit)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = rando
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_copy_edit)
|
|
||||||
assert not response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_proj_jt_admin_copy_edit(jt_copy_edit, rando):
|
|
||||||
"JT admins with access to associated resources SHOULD be able to copy"
|
|
||||||
|
|
||||||
# random user given JT and project admin abilities
|
|
||||||
jt_copy_edit.admin_role.members.add(rando)
|
|
||||||
jt_copy_edit.save()
|
|
||||||
jt_copy_edit.project.admin_role.members.add(rando)
|
|
||||||
jt_copy_edit.project.save()
|
|
||||||
|
|
||||||
# Serializer can_copy/can_edit fields
|
|
||||||
serializer = JobTemplateSerializer(jt_copy_edit)
|
|
||||||
request = RequestFactory().get('/api/v1/job_templates/12/')
|
|
||||||
request.user = rando
|
|
||||||
serializer.context['request'] = request
|
|
||||||
response = serializer.to_representation(jt_copy_edit)
|
|
||||||
assert response['summary_fields']['can_copy']
|
|
||||||
assert response['summary_fields']['can_edit']
|
|
||||||
|
|
||||||
# Functional tests - create new JT with all returned fields, as the UI does
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
@mock.patch.object(ProjectOptions, "playbooks", project_playbooks)
|
|
||||||
def test_org_admin_copy_edit_functional(jt_copy_edit, org_admin, get, post):
|
|
||||||
get_response = get(reverse('api:job_template_detail', args=[jt_copy_edit.pk]), user=org_admin)
|
|
||||||
assert get_response.status_code == 200
|
|
||||||
assert get_response.data['summary_fields']['can_copy']
|
|
||||||
|
|
||||||
post_data = get_response.data
|
|
||||||
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
|
|
||||||
post_response = post(reverse('api:job_template_list', args=[]), user=org_admin, data=post_data)
|
|
||||||
assert post_response.status_code == 201
|
|
||||||
assert post_response.data['name'] == 'copy-edit-job-template @ 12:19:47 pm'
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch.object(ProjectOptions, "playbooks", project_playbooks)
|
@mock.patch.object(ProjectOptions, "playbooks", project_playbooks)
|
||||||
@@ -277,7 +152,6 @@ def test_jt_admin_copy_edit_functional(jt_copy_edit, rando, get, post):
|
|||||||
|
|
||||||
get_response = get(reverse('api:job_template_detail', args=[jt_copy_edit.pk]), user=rando)
|
get_response = get(reverse('api:job_template_detail', args=[jt_copy_edit.pk]), user=rando)
|
||||||
assert get_response.status_code == 200
|
assert get_response.status_code == 200
|
||||||
assert not get_response.data['summary_fields']['can_copy']
|
|
||||||
|
|
||||||
post_data = get_response.data
|
post_data = get_response.data
|
||||||
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
|
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
|
||||||
|
|||||||
323
awx/main/tests/functional/api/test_rbac_displays.py
Normal file
323
awx/main/tests/functional/api/test_rbac_displays.py
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
|
from awx.main.models.jobs import JobTemplate
|
||||||
|
from awx.main.models import Role, Group
|
||||||
|
from awx.main.access import (
|
||||||
|
access_registry,
|
||||||
|
get_user_capabilities
|
||||||
|
)
|
||||||
|
from awx.main.utils import cache_list_capabilities
|
||||||
|
from awx.api.serializers import JobTemplateSerializer
|
||||||
|
|
||||||
|
# This file covers special-cases of displays of user_capabilities
|
||||||
|
# general functionality should be covered fully by unit tests, see:
|
||||||
|
# awx/main/tests/unit/api/test_serializers.py ::
|
||||||
|
# TestJobTemplateSerializerGetSummaryFields.test_copy_edit_standard
|
||||||
|
# awx/main/tests/unit/test_access.py ::
|
||||||
|
# test_user_capabilities_method
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestOptionsRBAC:
|
||||||
|
"""
|
||||||
|
Several endpoints are relied-upon by the UI to list POST as an
|
||||||
|
allowed action or not depending on whether the user has permission
|
||||||
|
to create a resource.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_inventory_group_host_can_add(self, inventory, alice, options):
|
||||||
|
inventory.admin_role.members.add(alice)
|
||||||
|
|
||||||
|
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), alice)
|
||||||
|
assert 'POST' in response.data['actions']
|
||||||
|
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), alice)
|
||||||
|
assert 'POST' in response.data['actions']
|
||||||
|
|
||||||
|
def test_inventory_group_host_can_not_add(self, inventory, bob, options):
|
||||||
|
inventory.read_role.members.add(bob)
|
||||||
|
|
||||||
|
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), bob)
|
||||||
|
assert 'POST' not in response.data['actions']
|
||||||
|
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), bob)
|
||||||
|
assert 'POST' not in response.data['actions']
|
||||||
|
|
||||||
|
def test_user_list_can_add(self, org_member, org_admin, options):
|
||||||
|
response = options(reverse('api:user_list'), org_admin)
|
||||||
|
assert 'POST' in response.data['actions']
|
||||||
|
|
||||||
|
def test_user_list_can_not_add(self, org_member, org_admin, options):
|
||||||
|
response = options(reverse('api:user_list'), org_member)
|
||||||
|
assert 'POST' not in response.data['actions']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestJobTemplateCopyEdit:
|
||||||
|
"""
|
||||||
|
Tests contain scenarios that were raised as issues in the past,
|
||||||
|
which resulted from failed copy/edit actions even though the buttons
|
||||||
|
to do these actions were displayed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def jt_copy_edit(self, job_template_factory, project):
|
||||||
|
objects = job_template_factory(
|
||||||
|
'copy-edit-job-template',
|
||||||
|
project=project)
|
||||||
|
return objects.job_template
|
||||||
|
|
||||||
|
def fake_context(self, user):
|
||||||
|
request = RequestFactory().get('/api/v1/resource/42/')
|
||||||
|
request.user = user
|
||||||
|
|
||||||
|
class FakeView(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
fake_view = FakeView()
|
||||||
|
fake_view.request = request
|
||||||
|
context = {}
|
||||||
|
context['view'] = fake_view
|
||||||
|
context['request'] = request
|
||||||
|
return context
|
||||||
|
|
||||||
|
def test_validation_bad_data_copy_edit(self, admin_user, project):
|
||||||
|
"""
|
||||||
|
If a required resource (inventory here) was deleted, copying not allowed
|
||||||
|
because doing so would caues a validation error
|
||||||
|
"""
|
||||||
|
|
||||||
|
jt_res = JobTemplate.objects.create(
|
||||||
|
job_type='run',
|
||||||
|
project=project,
|
||||||
|
inventory=None, ask_inventory_on_launch=False, # not allowed
|
||||||
|
credential=None, ask_credential_on_launch=True,
|
||||||
|
name='deploy-job-template'
|
||||||
|
)
|
||||||
|
serializer = JobTemplateSerializer(jt_res)
|
||||||
|
serializer.context = self.fake_context(admin_user)
|
||||||
|
response = serializer.to_representation(jt_res)
|
||||||
|
assert not response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
def test_sys_admin_copy_edit(self, jt_copy_edit, admin_user):
|
||||||
|
"Absent a validation error, system admins can do everything"
|
||||||
|
serializer = JobTemplateSerializer(jt_copy_edit)
|
||||||
|
serializer.context = self.fake_context(admin_user)
|
||||||
|
response = serializer.to_representation(jt_copy_edit)
|
||||||
|
assert response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
def test_org_admin_copy_edit(self, jt_copy_edit, org_admin):
|
||||||
|
"Organization admins SHOULD be able to copy a JT firmly in their org"
|
||||||
|
serializer = JobTemplateSerializer(jt_copy_edit)
|
||||||
|
serializer.context = self.fake_context(org_admin)
|
||||||
|
response = serializer.to_representation(jt_copy_edit)
|
||||||
|
assert response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
def test_org_admin_foreign_cred_no_copy_edit(self, jt_copy_edit, org_admin, machine_credential):
|
||||||
|
"""
|
||||||
|
Organization admins without access to the 3 related resources:
|
||||||
|
SHOULD NOT be able to copy JT
|
||||||
|
SHOULD be able to edit that job template, for nonsensitive changes
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Attach credential to JT that org admin can not use
|
||||||
|
jt_copy_edit.credential = machine_credential
|
||||||
|
jt_copy_edit.save()
|
||||||
|
|
||||||
|
serializer = JobTemplateSerializer(jt_copy_edit)
|
||||||
|
serializer.context = self.fake_context(org_admin)
|
||||||
|
response = serializer.to_representation(jt_copy_edit)
|
||||||
|
assert not response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
def test_jt_admin_copy_edit(self, jt_copy_edit, rando):
|
||||||
|
"""
|
||||||
|
JT admins wihout access to associated resources SHOULD NOT be able to copy
|
||||||
|
SHOULD be able to make nonsensitive changes"""
|
||||||
|
|
||||||
|
# random user given JT admin access only
|
||||||
|
jt_copy_edit.admin_role.members.add(rando)
|
||||||
|
jt_copy_edit.save()
|
||||||
|
|
||||||
|
serializer = JobTemplateSerializer(jt_copy_edit)
|
||||||
|
serializer.context = self.fake_context(rando)
|
||||||
|
response = serializer.to_representation(jt_copy_edit)
|
||||||
|
assert not response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
def test_proj_jt_admin_copy_edit(self, jt_copy_edit, rando):
|
||||||
|
"JT admins with access to associated resources SHOULD be able to copy"
|
||||||
|
|
||||||
|
# random user given JT and project admin abilities
|
||||||
|
jt_copy_edit.admin_role.members.add(rando)
|
||||||
|
jt_copy_edit.save()
|
||||||
|
jt_copy_edit.project.admin_role.members.add(rando)
|
||||||
|
jt_copy_edit.project.save()
|
||||||
|
|
||||||
|
serializer = JobTemplateSerializer(jt_copy_edit)
|
||||||
|
serializer.context = self.fake_context(rando)
|
||||||
|
response = serializer.to_representation(jt_copy_edit)
|
||||||
|
assert response['summary_fields']['user_capabilities']['copy']
|
||||||
|
assert response['summary_fields']['user_capabilities']['edit']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_access_method(mocker):
|
||||||
|
mock_method = mocker.MagicMock()
|
||||||
|
mock_method.return_value = 'foobar'
|
||||||
|
mock_method.__name__ = 'bars' # Required for a logging statement
|
||||||
|
return mock_method
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestAccessListCapabilities:
|
||||||
|
"""
|
||||||
|
Test that the access_list serializer shows the exact output of the RoleAccess.can_attach
|
||||||
|
- looks at /api/v1/inventories/N/access_list/
|
||||||
|
- test for types: direct, indirect, and team access
|
||||||
|
"""
|
||||||
|
|
||||||
|
extra_kwargs = dict(skip_sub_obj_read_check=False, data={})
|
||||||
|
|
||||||
|
def _assert_one_in_list(self, data, sublist='direct_access'):
|
||||||
|
"Establish that exactly 1 type of access exists so we know the entry is the right one"
|
||||||
|
assert len(data['results']) == 1
|
||||||
|
assert len(data['results'][0]['summary_fields'][sublist]) == 1
|
||||||
|
|
||||||
|
def test_access_list_direct_access_capability(
|
||||||
|
self, inventory, rando, get, mocker, mock_access_method):
|
||||||
|
inventory.admin_role.members.add(rando)
|
||||||
|
|
||||||
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
|
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), rando)
|
||||||
|
|
||||||
|
mock_access_method.assert_called_once_with(inventory.admin_role, rando, 'members', **self.extra_kwargs)
|
||||||
|
self._assert_one_in_list(response.data)
|
||||||
|
direct_access_list = response.data['results'][0]['summary_fields']['direct_access']
|
||||||
|
assert direct_access_list[0]['role']['user_capabilities']['unattach'] == 'foobar'
|
||||||
|
|
||||||
|
def test_access_list_indirect_access_capability(
|
||||||
|
self, inventory, organization, org_admin, get, mocker, mock_access_method):
|
||||||
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
|
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), org_admin)
|
||||||
|
|
||||||
|
mock_access_method.assert_called_once_with(organization.admin_role, org_admin, 'members', **self.extra_kwargs)
|
||||||
|
self._assert_one_in_list(response.data, sublist='indirect_access')
|
||||||
|
indirect_access_list = response.data['results'][0]['summary_fields']['indirect_access']
|
||||||
|
assert indirect_access_list[0]['role']['user_capabilities']['unattach'] == 'foobar'
|
||||||
|
|
||||||
|
def test_access_list_team_direct_access_capability(
|
||||||
|
self, inventory, team, team_member, get, mocker, mock_access_method):
|
||||||
|
team.member_role.children.add(inventory.admin_role)
|
||||||
|
|
||||||
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
|
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), team_member)
|
||||||
|
|
||||||
|
mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', **self.extra_kwargs)
|
||||||
|
self._assert_one_in_list(response.data)
|
||||||
|
direct_access_list = response.data['results'][0]['summary_fields']['direct_access']
|
||||||
|
assert direct_access_list[0]['role']['user_capabilities']['unattach'] == 'foobar'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_team_roles_unattach(mocker, team, team_member, inventory, mock_access_method, get):
|
||||||
|
team.member_role.children.add(inventory.admin_role)
|
||||||
|
|
||||||
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
|
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
|
||||||
|
|
||||||
|
# Did we assess whether team_member can remove team's permission to the inventory?
|
||||||
|
mock_access_method.assert_called_once_with(
|
||||||
|
inventory.admin_role, team.member_role, 'parents', skip_sub_obj_read_check=True, data={})
|
||||||
|
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach'] == 'foobar'
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_method, get):
|
||||||
|
# Add to same organization so that alice and bob can see each other
|
||||||
|
organization.member_role.members.add(alice)
|
||||||
|
organization.member_role.members.add(bob)
|
||||||
|
|
||||||
|
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
|
||||||
|
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
|
||||||
|
|
||||||
|
# Did we assess whether bob can remove alice's permission to the inventory?
|
||||||
|
mock_access_method.assert_called_once_with(
|
||||||
|
organization.member_role, alice, 'members', skip_sub_obj_read_check=True, data={})
|
||||||
|
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach'] == 'foobar'
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_team_roles_unattach_functional(team, team_member, inventory, get):
|
||||||
|
team.member_role.children.add(inventory.admin_role)
|
||||||
|
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
|
||||||
|
# Team member should be able to remove access to inventory, becauase
|
||||||
|
# the inventory admin_role grants that ability
|
||||||
|
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_user_roles_unattach_functional(organization, alice, bob, get):
|
||||||
|
organization.member_role.members.add(alice)
|
||||||
|
organization.member_role.members.add(bob)
|
||||||
|
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
|
||||||
|
# Org members can not revoke the membership of other members
|
||||||
|
assert not response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_prefetch_jt_capabilities(job_template, rando):
|
||||||
|
job_template.execute_role.members.add(rando)
|
||||||
|
qs = JobTemplate.objects.all()
|
||||||
|
cache_list_capabilities(qs, ['admin', 'execute'], JobTemplate, rando)
|
||||||
|
assert qs[0].capabilities_cache == {'edit': False, 'start': True}
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_prefetch_group_capabilities(group, rando):
|
||||||
|
group.inventory.adhoc_role.members.add(rando)
|
||||||
|
qs = Group.objects.all()
|
||||||
|
cache_list_capabilities(qs, ['inventory.admin', 'inventory.adhoc'], Group, rando)
|
||||||
|
assert qs[0].capabilities_cache == {'edit': False, 'adhoc': True}
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_prefetch_jt_copy_capability(job_template, project, inventory, machine_credential, rando):
|
||||||
|
job_template.project = project
|
||||||
|
job_template.inventory = inventory
|
||||||
|
job_template.credential = machine_credential
|
||||||
|
job_template.save()
|
||||||
|
|
||||||
|
qs = JobTemplate.objects.all()
|
||||||
|
cache_list_capabilities(qs, [{'copy': [
|
||||||
|
'project.use', 'inventory.use', 'credential.use',
|
||||||
|
'cloud_credential.use', 'network_credential.use'
|
||||||
|
]}], JobTemplate, rando)
|
||||||
|
assert qs[0].capabilities_cache == {'copy': False}
|
||||||
|
|
||||||
|
project.use_role.members.add(rando)
|
||||||
|
inventory.use_role.members.add(rando)
|
||||||
|
machine_credential.use_role.members.add(rando)
|
||||||
|
|
||||||
|
cache_list_capabilities(qs, [{'copy': [
|
||||||
|
'project.use', 'inventory.use', 'credential.use',
|
||||||
|
'cloud_credential.use', 'network_credential.use'
|
||||||
|
]}], JobTemplate, rando)
|
||||||
|
assert qs[0].capabilities_cache == {'copy': True}
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_group_update_capabilities_possible(group, inventory_source, admin_user):
|
||||||
|
group.inventory_source = inventory_source
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
capabilities = get_user_capabilities(admin_user, group, method_list=['start'])
|
||||||
|
assert capabilities['start']
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_group_update_capabilities_impossible(group, inventory_source, admin_user):
|
||||||
|
inventory_source.source = ""
|
||||||
|
inventory_source.save()
|
||||||
|
group.inventory_source = inventory_source
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
capabilities = get_user_capabilities(admin_user, group, method_list=['start'])
|
||||||
|
assert not capabilities['start']
|
||||||
|
|
||||||
@@ -6,9 +6,13 @@ import mock
|
|||||||
from awx.api.serializers import (
|
from awx.api.serializers import (
|
||||||
JobTemplateSerializer,
|
JobTemplateSerializer,
|
||||||
)
|
)
|
||||||
|
from awx.api.views import JobTemplateDetail
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
|
Role,
|
||||||
|
User,
|
||||||
Job,
|
Job,
|
||||||
)
|
)
|
||||||
|
from rest_framework.test import APIRequestFactory
|
||||||
|
|
||||||
#DRF
|
#DRF
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
@@ -77,21 +81,33 @@ class TestJobTemplateSerializerGetSummaryFields():
|
|||||||
summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template)
|
summary = get_summary_fields_mock_and_run(JobTemplateSerializer, job_template)
|
||||||
assert 'survey' not in summary
|
assert 'survey' not in summary
|
||||||
|
|
||||||
@pytest.mark.skip(reason="RBAC needs to land")
|
def test_copy_edit_standard(self, mocker, job_template_factory):
|
||||||
def test_can_copy_true(self, mocker, job_template):
|
"""Verify that the exact output of the access.py methods
|
||||||
pass
|
are put into the serializer user_capabilities"""
|
||||||
|
|
||||||
@pytest.mark.skip(reason="RBAC needs to land")
|
jt_obj = job_template_factory('testJT', project='proj1', persisted=False).job_template
|
||||||
def test_can_copy_false(self, mocker, job_template):
|
jt_obj.id = 5
|
||||||
pass
|
jt_obj.admin_role = Role(id=9, role_field='admin_role')
|
||||||
|
jt_obj.execute_role = Role(id=8, role_field='execute_role')
|
||||||
|
jt_obj.read_role = Role(id=7, role_field='execute_role')
|
||||||
|
user = User(username="auser")
|
||||||
|
serializer = JobTemplateSerializer(job_template)
|
||||||
|
serializer.show_capabilities = ['copy', 'edit']
|
||||||
|
serializer._summary_field_labels = lambda self: []
|
||||||
|
serializer._recent_jobs = lambda self: []
|
||||||
|
request = APIRequestFactory().get('/api/v1/job_templates/42/')
|
||||||
|
request.user = user
|
||||||
|
view = JobTemplateDetail()
|
||||||
|
view.request = request
|
||||||
|
serializer.context['view'] = view
|
||||||
|
|
||||||
@pytest.mark.skip(reason="RBAC needs to land")
|
with mocker.patch("awx.main.models.rbac.Role.get_description", return_value='Can eat pie'):
|
||||||
def test_can_edit_true(self, mocker, job_template):
|
with mocker.patch("awx.main.access.JobTemplateAccess.can_change", return_value='foobar'):
|
||||||
pass
|
with mocker.patch("awx.main.access.JobTemplateAccess.can_add", return_value='foo'):
|
||||||
|
response = serializer.get_summary_fields(jt_obj)
|
||||||
|
|
||||||
@pytest.mark.skip(reason="RBAC needs to land")
|
assert response['user_capabilities']['copy'] == 'foo'
|
||||||
def test_can_edit_false(self, mocker, job_template):
|
assert response['user_capabilities']['edit'] == 'foobar'
|
||||||
pass
|
|
||||||
|
|
||||||
class TestJobTemplateSerializerValidation(object):
|
class TestJobTemplateSerializerValidation(object):
|
||||||
|
|
||||||
|
|||||||
@@ -50,3 +50,32 @@ def test_job_template_survey_password_redaction(job_template_with_survey_passwor
|
|||||||
"""Tests the JobTemplate model's funciton to redact passwords from
|
"""Tests the JobTemplate model's funciton to redact passwords from
|
||||||
extra_vars - used when creating a new job"""
|
extra_vars - used when creating a new job"""
|
||||||
assert job_template_with_survey_passwords_unit.survey_password_variables() == ['secret_key', 'SSN']
|
assert job_template_with_survey_passwords_unit.survey_password_variables() == ['secret_key', 'SSN']
|
||||||
|
|
||||||
|
def test_job_template_survey_variable_validation(job_template_factory):
|
||||||
|
objects = job_template_factory(
|
||||||
|
'survey_variable_validation',
|
||||||
|
organization='org1',
|
||||||
|
inventory='inventory1',
|
||||||
|
credential='cred1',
|
||||||
|
persisted=False,
|
||||||
|
)
|
||||||
|
obj = objects.job_template
|
||||||
|
obj.survey_spec = {
|
||||||
|
"description": "",
|
||||||
|
"spec": [
|
||||||
|
{
|
||||||
|
"required": True,
|
||||||
|
"min": 0,
|
||||||
|
"default": "5",
|
||||||
|
"max": 1024,
|
||||||
|
"question_description": "",
|
||||||
|
"choices": "",
|
||||||
|
"variable": "a",
|
||||||
|
"question_name": "Whosyourdaddy",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
obj.survey_enabled = True
|
||||||
|
assert obj.survey_variable_validation({"a": 5}) == ["Value 5 for 'a' expected to be a string."]
|
||||||
|
|||||||
@@ -134,3 +134,28 @@ class TestWorkflowAccessMethods:
|
|||||||
with mock.patch('awx.main.access.get_object_or_400', mock_get_object):
|
with mock.patch('awx.main.access.get_object_or_400', mock_get_object):
|
||||||
assert access.can_add({'organization': 1})
|
assert access.can_add({'organization': 1})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_user_capabilities_method():
|
||||||
|
"""Unit test to verify that the user_capabilities method will defer
|
||||||
|
to the appropriate sub-class methods of the access classes.
|
||||||
|
Note that normal output is True/False, but a string is returned
|
||||||
|
in these tests to establish uniqueness.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class FooAccess(BaseAccess):
|
||||||
|
def can_change(self, obj, data):
|
||||||
|
return 'bar'
|
||||||
|
|
||||||
|
def can_add(self, data):
|
||||||
|
return 'foobar'
|
||||||
|
|
||||||
|
user = User(username='auser')
|
||||||
|
foo_access = FooAccess(user)
|
||||||
|
foo = object()
|
||||||
|
foo_capabilities = foo_access.get_user_capabilities(foo, ['edit', 'copy'])
|
||||||
|
assert foo_capabilities == {
|
||||||
|
'edit': 'bar',
|
||||||
|
'copy': 'foobar'
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ def test_net_cred_ssh_agent(mocker, get_ssh_version):
|
|||||||
mocker.patch.object(run_job, 'should_use_proot', return_value=False)
|
mocker.patch.object(run_job, 'should_use_proot', return_value=False)
|
||||||
mocker.patch.object(run_job, 'run_pexpect', return_value=('successful', 0))
|
mocker.patch.object(run_job, 'run_pexpect', return_value=('successful', 0))
|
||||||
mocker.patch.object(run_job, 'open_fifo_write', return_value=None)
|
mocker.patch.object(run_job, 'open_fifo_write', return_value=None)
|
||||||
|
mocker.patch.object(run_job, 'post_run_hook', return_value=None)
|
||||||
|
|
||||||
run_job.run(mock_job.id)
|
run_job.run(mock_job.id)
|
||||||
assert run_job.update_model.call_count == 3
|
assert run_job.update_model.call_count == 3
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ logger = logging.getLogger('awx.main.utils')
|
|||||||
|
|
||||||
__all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore', 'memoize',
|
__all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore', 'memoize',
|
||||||
'get_ansible_version', 'get_ssh_version', 'get_awx_version', 'update_scm_url',
|
'get_ansible_version', 'get_ssh_version', 'get_awx_version', 'update_scm_url',
|
||||||
'get_type_for_model', 'get_model_for_type', 'to_python_boolean',
|
'get_type_for_model', 'get_model_for_type', 'cache_list_capabilities', 'to_python_boolean',
|
||||||
'ignore_inventory_computed_fields', 'ignore_inventory_group_removal',
|
'ignore_inventory_computed_fields', 'ignore_inventory_group_removal',
|
||||||
'_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided',
|
'_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided',
|
||||||
'get_current_apps', 'set_current_apps']
|
'get_current_apps', 'set_current_apps']
|
||||||
@@ -409,6 +409,72 @@ def get_model_for_type(type):
|
|||||||
return ct_model
|
return ct_model
|
||||||
|
|
||||||
|
|
||||||
|
def cache_list_capabilities(page, prefetch_list, model, user):
|
||||||
|
'''
|
||||||
|
Given a `page` list of objects, the specified roles for the specified user
|
||||||
|
are save on each object in the list, using 1 query for each role type
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
capabilities_prefetch = ['admin', 'execute']
|
||||||
|
--> prefetch the admin (edit) and execute (start) permissions for
|
||||||
|
items in list for current user
|
||||||
|
capabilities_prefetch = ['inventory.admin']
|
||||||
|
--> prefetch the related inventory FK permissions for current user,
|
||||||
|
and put it into the object's cache
|
||||||
|
capabilities_prefetch = [{'copy': ['inventory.admin', 'project.admin']}]
|
||||||
|
--> prefetch logical combination of admin permission to inventory AND
|
||||||
|
project, put into cache dictionary as "copy"
|
||||||
|
'''
|
||||||
|
from django.db.models import Q
|
||||||
|
page_ids = [obj.id for obj in page]
|
||||||
|
for obj in page:
|
||||||
|
obj.capabilities_cache = {}
|
||||||
|
|
||||||
|
for prefetch_entry in prefetch_list:
|
||||||
|
|
||||||
|
display_method = None
|
||||||
|
if type(prefetch_entry) is dict:
|
||||||
|
display_method = prefetch_entry.keys()[0]
|
||||||
|
paths = prefetch_entry[display_method]
|
||||||
|
else:
|
||||||
|
paths = prefetch_entry
|
||||||
|
|
||||||
|
if type(paths) is not list:
|
||||||
|
paths = [paths]
|
||||||
|
|
||||||
|
# Build the query for accessible_objects according the user & role(s)
|
||||||
|
qs_obj = None
|
||||||
|
for role_path in paths:
|
||||||
|
if '.' in role_path:
|
||||||
|
res_path = '__'.join(role_path.split('.')[:-1])
|
||||||
|
role_type = role_path.split('.')[-1]
|
||||||
|
if qs_obj is None:
|
||||||
|
qs_obj = model.objects
|
||||||
|
parent_model = model._meta.get_field(res_path).related_model
|
||||||
|
kwargs = {'%s__in' % res_path: parent_model.accessible_objects(user, '%s_role' % role_type)}
|
||||||
|
qs_obj = qs_obj.filter(Q(**kwargs) | Q(**{'%s__isnull' % res_path: True}))
|
||||||
|
else:
|
||||||
|
role_type = role_path
|
||||||
|
qs_obj = model.accessible_objects(user, '%s_role' % role_type)
|
||||||
|
|
||||||
|
if display_method is None:
|
||||||
|
# Role name translation to UI names for methods
|
||||||
|
display_method = role_type
|
||||||
|
if role_type == 'admin':
|
||||||
|
display_method = 'edit'
|
||||||
|
elif role_type in ['execute', 'update']:
|
||||||
|
display_method = 'start'
|
||||||
|
|
||||||
|
# Union that query with the list of items on page
|
||||||
|
ids_with_role = set(qs_obj.filter(pk__in=page_ids).values_list('pk', flat=True))
|
||||||
|
|
||||||
|
# Save data item-by-item
|
||||||
|
for obj in page:
|
||||||
|
obj.capabilities_cache[display_method] = False
|
||||||
|
if obj.pk in ids_with_role:
|
||||||
|
obj.capabilities_cache[display_method] = True
|
||||||
|
|
||||||
|
|
||||||
def get_system_task_capacity():
|
def get_system_task_capacity():
|
||||||
'''
|
'''
|
||||||
Measure system memory and use it as a baseline for determining the system's capacity
|
Measure system memory and use it as a baseline for determining the system's capacity
|
||||||
|
|||||||
1
awx/ui/.npmrc
Normal file
1
awx/ui/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
progress=false
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<div class="RoleList-tagContainer"
|
<div class="RoleList-tagContainer"
|
||||||
ng-repeat="entry in access_list">
|
ng-repeat="entry in access_list">
|
||||||
<div class="RoleList-deleteContainer"
|
<div class="RoleList-deleteContainer"
|
||||||
ng-if="entry.explicit"
|
ng-if="entry.explicit && entry.user_capabilities.unattach"
|
||||||
ng-click="deletePermission(permission, entry)">
|
ng-click="deletePermission(permission, entry)">
|
||||||
<i ng-if="entry.explicit"
|
<i ng-if="entry.explicit && entry.user_capabilities.unattach"
|
||||||
class="fa fa-times RoleList-tagDelete"></i>
|
class="fa fa-times RoleList-tagDelete"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="RoleList-tag"
|
<div class="RoleList-tag"
|
||||||
ng-class="{'RoleList-tag--deletable': entry.explicit,
|
ng-class="{'RoleList-tag--deletable': entry.explicit && entry.user_capabilities.unattach,
|
||||||
'RoleList-tag--team': entry.team_id}"
|
'RoleList-tag--team': entry.team_id}"
|
||||||
aw-tool-tip='{{entry.team_name | sanitize}}' aw-tip-placement='bottom'>
|
aw-tool-tip='{{entry.team_name | sanitize}}' aw-tip-placement='bottom'>
|
||||||
<span class="RoleList-name">{{ entry.name }}</span>
|
<span class="RoleList-name">{{ entry.name }}</span>
|
||||||
|
|||||||
@@ -839,6 +839,7 @@ var tower = angular.module('Tower', [
|
|||||||
// If browser refresh, set the user_is_superuser value
|
// If browser refresh, set the user_is_superuser value
|
||||||
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
|
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
|
||||||
$rootScope.user_is_system_auditor = Authorization.getUserInfo('is_system_auditor');
|
$rootScope.user_is_system_auditor = Authorization.getUserInfo('is_system_auditor');
|
||||||
|
|
||||||
// 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)
|
// 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')) {
|
if (!_.contains($location.$$url, '/login')) {
|
||||||
ConfigService.getConfig().then(function() {
|
ConfigService.getConfig().then(function() {
|
||||||
|
|||||||
@@ -14,9 +14,14 @@
|
|||||||
export function CredentialsList($scope, $rootScope, $location, $log,
|
export function CredentialsList($scope, $rootScope, $location, $log,
|
||||||
$stateParams, Rest, Alert, CredentialList, GenerateList, Prompt, SearchInit,
|
$stateParams, Rest, Alert, CredentialList, GenerateList, Prompt, SearchInit,
|
||||||
PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
||||||
SelectionInit, GetChoices, Wait, $state, $filter) {
|
SelectionInit, GetChoices, Wait, $state, $filter, rbacUiControlService) {
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd('credentials')
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
|
|
||||||
var list = CredentialList,
|
var list = CredentialList,
|
||||||
@@ -129,7 +134,7 @@ CredentialsList.$inject = ['$scope', '$rootScope', '$location', '$log',
|
|||||||
'$stateParams', 'Rest', 'Alert', 'CredentialList', 'generateList', 'Prompt',
|
'$stateParams', 'Rest', 'Alert', 'CredentialList', 'generateList', 'Prompt',
|
||||||
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'GetChoices', 'Wait',
|
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'GetChoices', 'Wait',
|
||||||
'$state', '$filter'
|
'$state', '$filter', 'rbacUiControlService'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +143,6 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
ReturnToCaller, ClearScope, GenerateList, SearchInit, PaginateInit,
|
ReturnToCaller, ClearScope, GenerateList, SearchInit, PaginateInit,
|
||||||
LookUpInit, OrganizationList, GetBasePath, GetChoices, Empty, KindChange,
|
LookUpInit, OrganizationList, GetBasePath, GetChoices, Empty, KindChange,
|
||||||
OwnerChange, FormSave, $state, CreateSelect2) {
|
OwnerChange, FormSave, $state, CreateSelect2) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
@@ -337,6 +341,7 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
var defaultUrl = GetBasePath('credentials'),
|
var defaultUrl = GetBasePath('credentials'),
|
||||||
generator = GenerateForm,
|
generator = GenerateForm,
|
||||||
form = CredentialForm,
|
form = CredentialForm,
|
||||||
@@ -344,10 +349,17 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
master = {},
|
master = {},
|
||||||
id = $stateParams.credential_id,
|
id = $stateParams.credential_id,
|
||||||
relatedSets = {};
|
relatedSets = {};
|
||||||
|
|
||||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
||||||
generator.reset();
|
generator.reset();
|
||||||
$scope.id = id;
|
$scope.id = id;
|
||||||
|
|
||||||
|
$scope.$watch('credential_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$scope.canShareCredential = false;
|
$scope.canShareCredential = false;
|
||||||
|
|
||||||
if ($rootScope.current_user.is_superuser) {
|
if ($rootScope.current_user.is_superuser) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
export function JobsListController ($rootScope, $log, $scope, $compile, $stateParams,
|
export function JobsListController ($rootScope, $log, $scope, $compile, $stateParams,
|
||||||
ClearScope, LoadSchedulesScope,
|
ClearScope, LoadSchedulesScope,
|
||||||
LoadJobsScope, AllJobsList, ScheduledJobsList, GetChoices, GetBasePath, Wait) {
|
LoadJobsScope, AllJobsList, ScheduledJobsList, GetChoices, GetBasePath, Wait, $state) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
@@ -61,6 +61,11 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs_scope = $scope.$new(true);
|
jobs_scope = $scope.$new(true);
|
||||||
|
|
||||||
|
jobs_scope.viewJob = function (id) {
|
||||||
|
$state.transitionTo('jobDetail', {id: id});
|
||||||
|
};
|
||||||
|
|
||||||
jobs_scope.showJobType = true;
|
jobs_scope.showJobType = true;
|
||||||
LoadJobsScope({
|
LoadJobsScope({
|
||||||
parent_scope: $scope,
|
parent_scope: $scope,
|
||||||
@@ -153,4 +158,4 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa
|
|||||||
|
|
||||||
JobsListController.$inject = ['$rootScope', '$log', '$scope', '$compile', '$stateParams',
|
JobsListController.$inject = ['$rootScope', '$log', '$scope', '$compile', '$stateParams',
|
||||||
'ClearScope', 'LoadSchedulesScope', 'LoadJobsScope',
|
'ClearScope', 'LoadSchedulesScope', 'LoadJobsScope',
|
||||||
'AllJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait'];
|
'AllJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', '$state'];
|
||||||
|
|||||||
@@ -15,10 +15,16 @@ export function ProjectsList ($scope, $rootScope, $location, $log, $stateParams,
|
|||||||
Rest, Alert, ProjectList, GenerateList, Prompt, SearchInit,
|
Rest, Alert, ProjectList, GenerateList, Prompt, SearchInit,
|
||||||
PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath,
|
||||||
SelectionInit, ProjectUpdate, Refresh, Wait, GetChoices, Empty,
|
SelectionInit, ProjectUpdate, Refresh, Wait, GetChoices, Empty,
|
||||||
Find, GetProjectIcon, GetProjectToolTip, $filter, $state) {
|
Find, GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd('projects')
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
|
|
||||||
var list = ProjectList,
|
var list = ProjectList,
|
||||||
@@ -369,7 +375,7 @@ ProjectsList.$inject = ['$scope', '$rootScope', '$location', '$log',
|
|||||||
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'ProjectUpdate',
|
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'ProjectUpdate',
|
||||||
'Refresh', 'Wait', 'GetChoices', 'Empty', 'Find',
|
'Refresh', 'Wait', 'GetChoices', 'Empty', 'Find',
|
||||||
'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state'
|
'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state', 'rbacUiControlService'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -379,6 +385,15 @@ export function ProjectsAdd(Refresh, $scope, $rootScope, $compile, $location, $l
|
|||||||
OrganizationList, CredentialList, GetChoices, DebugForm, Wait, $state,
|
OrganizationList, CredentialList, GetChoices, DebugForm, Wait, $state,
|
||||||
CreateSelect2) {
|
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();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
@@ -559,6 +574,12 @@ export function ProjectsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
|
|
||||||
ClearScope('htmlTemplate');
|
ClearScope('htmlTemplate');
|
||||||
|
|
||||||
|
$scope.$watch('project_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
var form = ProjectsForm(),
|
var form = ProjectsForm(),
|
||||||
generator = GenerateForm,
|
generator = GenerateForm,
|
||||||
|
|||||||
@@ -14,10 +14,16 @@
|
|||||||
export function TeamsList($scope, $rootScope, $location, $log, $stateParams,
|
export function TeamsList($scope, $rootScope, $location, $log, $stateParams,
|
||||||
Rest, Alert, TeamList, GenerateList, Prompt, SearchInit, PaginateInit,
|
Rest, Alert, TeamList, GenerateList, Prompt, SearchInit, PaginateInit,
|
||||||
ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath,
|
ReturnToCaller, ClearScope, ProcessErrors, SetTeamListeners, GetBasePath,
|
||||||
SelectionInit, Wait, $state, Refresh, $filter) {
|
SelectionInit, Wait, $state, Refresh, $filter, rbacUiControlService) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd('teams')
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
var list = TeamList,
|
var list = TeamList,
|
||||||
defaultUrl = GetBasePath('teams'),
|
defaultUrl = GetBasePath('teams'),
|
||||||
generator = GenerateList,
|
generator = GenerateList,
|
||||||
@@ -126,7 +132,7 @@ TeamsList.$inject = ['$scope', '$rootScope', '$location', '$log',
|
|||||||
'$stateParams', 'Rest', 'Alert', 'TeamList', 'generateList', 'Prompt',
|
'$stateParams', 'Rest', 'Alert', 'TeamList', 'generateList', 'Prompt',
|
||||||
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait',
|
'ProcessErrors', 'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait',
|
||||||
'$state', 'Refresh', '$filter'
|
'$state', 'Refresh', '$filter', 'rbacUiControlService'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -137,6 +143,15 @@ export function TeamsAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||||
//$scope.
|
//$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
|
// Inject dynamic view
|
||||||
var defaultUrl = GetBasePath('teams'),
|
var defaultUrl = GetBasePath('teams'),
|
||||||
form = TeamForm,
|
form = TeamForm,
|
||||||
@@ -208,6 +223,12 @@ export function TeamsEdit($scope, $rootScope, $location,
|
|||||||
|
|
||||||
$scope.team_id = id;
|
$scope.team_id = id;
|
||||||
|
|
||||||
|
$scope.$watch('team_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
||||||
generator.reset();
|
generator.reset();
|
||||||
|
|||||||
@@ -34,10 +34,16 @@ function user_type_sync($scope) {
|
|||||||
export function UsersList($scope, $rootScope, $location, $log, $stateParams,
|
export function UsersList($scope, $rootScope, $location, $log, $stateParams,
|
||||||
Rest, Alert, UserList, GenerateList, Prompt, SearchInit, PaginateInit,
|
Rest, Alert, UserList, GenerateList, Prompt, SearchInit, PaginateInit,
|
||||||
ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit,
|
ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit,
|
||||||
Wait, $state, Refresh, $filter) {
|
Wait, $state, Refresh, $filter, rbacUiControlService) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd('users')
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
var list = UserList,
|
var list = UserList,
|
||||||
defaultUrl = GetBasePath('users'),
|
defaultUrl = GetBasePath('users'),
|
||||||
generator = GenerateList,
|
generator = GenerateList,
|
||||||
@@ -136,7 +142,7 @@ UsersList.$inject = ['$scope', '$rootScope', '$location', '$log',
|
|||||||
'$stateParams', 'Rest', 'Alert', 'UserList', 'generateList', 'Prompt',
|
'$stateParams', 'Rest', 'Alert', 'UserList', 'generateList', 'Prompt',
|
||||||
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'Wait', '$state',
|
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'Wait', '$state',
|
||||||
'Refresh', '$filter'
|
'Refresh', '$filter', 'rbacUiControlService'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -148,6 +154,15 @@ export function UsersAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
ReturnToCaller, ClearScope, GetBasePath, LookUpInit, OrganizationList,
|
ReturnToCaller, ClearScope, GetBasePath, LookUpInit, OrganizationList,
|
||||||
ResetForm, Wait, CreateSelect2, $state) {
|
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();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
@@ -279,6 +294,12 @@ export function UsersEdit($scope, $rootScope, $location,
|
|||||||
$scope.user_type = user_type_options[0];
|
$scope.user_type = user_type_options[0];
|
||||||
$scope.$watch('user_type', user_type_sync($scope));
|
$scope.$watch('user_type', user_type_sync($scope));
|
||||||
|
|
||||||
|
$scope.$watch('user_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var setScopeFields = function(data){
|
var setScopeFields = function(data){
|
||||||
_(data)
|
_(data)
|
||||||
.pick(function(value, key){
|
.pick(function(value, key){
|
||||||
|
|||||||
@@ -32,13 +32,15 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
autocomplete: false
|
autocomplete: false,
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
@@ -52,7 +54,8 @@ export default
|
|||||||
awPopOver: "<p>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.</p>",
|
awPopOver: "<p>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.</p>",
|
||||||
dataTitle: 'Organization ',
|
dataTitle: 'Organization ',
|
||||||
dataPlacement: 'bottom',
|
dataPlacement: 'bottom',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
kind: {
|
kind: {
|
||||||
label: 'Type',
|
label: 'Type',
|
||||||
@@ -83,7 +86,8 @@ export default
|
|||||||
dataTitle: 'Type',
|
dataTitle: 'Type',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
hasSubForm: true
|
hasSubForm: true,
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
access_key: {
|
access_key: {
|
||||||
label: 'Access Key',
|
label: 'Access Key',
|
||||||
@@ -96,12 +100,13 @@ export default
|
|||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
apiField: 'username',
|
apiField: 'username',
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
secret_key: {
|
secret_key: {
|
||||||
label: 'Secret Key',
|
label: 'Secret Key',
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
ngShow: "kind.value == 'aws'",
|
ngShow: "kind.value == 'aws'",
|
||||||
ngDisabled: "secret_key_ask",
|
ngDisabled: "secret_key_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "aws_required",
|
reqExpression: "aws_required",
|
||||||
init: false
|
init: false
|
||||||
@@ -123,7 +128,8 @@ export default
|
|||||||
dataTitle: 'STS Token',
|
dataTitle: 'STS Token',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
labelBind: 'hostLabel',
|
labelBind: 'hostLabel',
|
||||||
@@ -139,7 +145,8 @@ export default
|
|||||||
reqExpression: 'host_required',
|
reqExpression: 'host_required',
|
||||||
init: false
|
init: false
|
||||||
},
|
},
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
label: "Subscription ID",
|
label: "Subscription ID",
|
||||||
@@ -156,7 +163,8 @@ export default
|
|||||||
dataTitle: 'Subscription ID',
|
dataTitle: 'Subscription ID',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
labelBind: 'usernameLabel',
|
labelBind: 'usernameLabel',
|
||||||
@@ -168,7 +176,8 @@ export default
|
|||||||
init: false
|
init: false
|
||||||
},
|
},
|
||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
subForm: "credentialSubForm"
|
subForm: "credentialSubForm",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"email_address": {
|
"email_address": {
|
||||||
labelBind: 'usernameLabel',
|
labelBind: 'usernameLabel',
|
||||||
@@ -183,7 +192,8 @@ export default
|
|||||||
dataTitle: 'Email',
|
dataTitle: 'Email',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"api_key": {
|
"api_key": {
|
||||||
label: 'API Key',
|
label: 'API Key',
|
||||||
@@ -196,7 +206,8 @@ export default
|
|||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
hasShowInputButton: true,
|
hasShowInputButton: true,
|
||||||
clear: false,
|
clear: false,
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
labelBind: 'passwordLabel',
|
labelBind: 'passwordLabel',
|
||||||
@@ -209,13 +220,14 @@ export default
|
|||||||
reqExpression: "password_required",
|
reqExpression: "password_required",
|
||||||
init: false
|
init: false
|
||||||
},
|
},
|
||||||
subForm: "credentialSubForm"
|
subForm: "credentialSubForm",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"ssh_password": {
|
"ssh_password": {
|
||||||
label: 'Password',
|
label: 'Password',
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
ngShow: "kind.value == 'ssh'",
|
ngShow: "kind.value == 'ssh'",
|
||||||
ngDisabled: "ssh_password_ask",
|
ngDisabled: "ssh_password_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
@@ -247,7 +259,8 @@ export default
|
|||||||
dataTitle: 'Private Key',
|
dataTitle: 'Private Key',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
subForm: "credentialSubForm"
|
subForm: "credentialSubForm",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"ssh_key_unlock": {
|
"ssh_key_unlock": {
|
||||||
label: 'Private Key Passphrase',
|
label: 'Private Key Passphrase',
|
||||||
@@ -255,7 +268,7 @@ export default
|
|||||||
ngShow: "kind.value == 'ssh' || kind.value == 'scm'",
|
ngShow: "kind.value == 'ssh' || kind.value == 'scm'",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
ngDisabled: "keyEntered === false || ssh_key_unlock_ask",
|
ngDisabled: "keyEntered === false || ssh_key_unlock_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ssh_key_unlock_ask',
|
variable: 'ssh_key_unlock_ask',
|
||||||
ngShow: "kind.value == 'ssh'",
|
ngShow: "kind.value == 'ssh'",
|
||||||
@@ -278,7 +291,8 @@ export default
|
|||||||
"<code>sudo | su | pbrun | pfexec | runas</code> <br>(defaults to <code>sudo</code>)</p>",
|
"<code>sudo | su | pbrun | pfexec | runas</code> <br>(defaults to <code>sudo</code>)</p>",
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"become_username": {
|
"become_username": {
|
||||||
labelBind: 'becomeUsernameLabel',
|
labelBind: 'becomeUsernameLabel',
|
||||||
@@ -287,13 +301,14 @@ export default
|
|||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"become_password": {
|
"become_password": {
|
||||||
labelBind: 'becomePasswordLabel',
|
labelBind: 'becomePasswordLabel',
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
ngShow: "(kind.value == 'ssh' && (become_method && become_method.value)) ",
|
ngShow: "(kind.value == 'ssh' && (become_method && become_method.value)) ",
|
||||||
ngDisabled: "become_password_ask",
|
ngDisabled: "become_password_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
@@ -309,7 +324,8 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
label: 'Client ID',
|
label: 'Client ID',
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
ngShow: "kind.value === 'azure_rm'"
|
ngShow: "kind.value === 'azure_rm'",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
secret:{
|
secret:{
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
@@ -317,20 +333,23 @@ export default
|
|||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
label: 'Client Secret',
|
label: 'Client Secret',
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
ngShow: "kind.value === 'azure_rm'"
|
ngShow: "kind.value === 'azure_rm'",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
tenant: {
|
tenant: {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
label: 'Tenant ID',
|
label: 'Tenant ID',
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
ngShow: "kind.value === 'azure_rm'"
|
ngShow: "kind.value === 'azure_rm'",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
authorize: {
|
authorize: {
|
||||||
label: 'Authorize',
|
label: 'Authorize',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
ngChange: "toggleCallback('host_config_key')",
|
ngChange: "toggleCallback('host_config_key')",
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
ngShow: "kind.value === 'net'"
|
ngShow: "kind.value === 'net'",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
authorize_password: {
|
authorize_password: {
|
||||||
label: 'Authorize Password',
|
label: 'Authorize Password',
|
||||||
@@ -339,6 +358,7 @@ export default
|
|||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
subForm: 'credentialSubForm',
|
subForm: 'credentialSubForm',
|
||||||
ngShow: "authorize && authorize !== 'false'",
|
ngShow: "authorize && authorize !== 'false'",
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
labelBind: 'projectLabel',
|
labelBind: 'projectLabel',
|
||||||
@@ -355,7 +375,8 @@ export default
|
|||||||
reqExpression: 'project_required',
|
reqExpression: 'project_required',
|
||||||
init: false
|
init: false
|
||||||
},
|
},
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"domain": {
|
"domain": {
|
||||||
labelBind: 'domainLabel',
|
labelBind: 'domainLabel',
|
||||||
@@ -371,13 +392,14 @@ export default
|
|||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subForm: 'credentialSubForm'
|
subForm: 'credentialSubForm',
|
||||||
|
ngDisabled: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
"vault_password": {
|
"vault_password": {
|
||||||
label: "Vault Password",
|
label: "Vault Password",
|
||||||
type: 'sensitive',
|
type: 'sensitive',
|
||||||
ngShow: "kind.value == 'ssh'",
|
ngShow: "kind.value == 'ssh'",
|
||||||
ngDisabled: "vault_password_ask",
|
ngDisabled: "vault_password_ask || !(credential_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
@@ -394,11 +416,17 @@ export default
|
|||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()',
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
label: 'Save',
|
label: 'Save',
|
||||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
ngDisabled: true,
|
||||||
|
ngShow: '(credential_obj.summary_fields.user_capabilities.edit || canAdd)' //Disable when $pristine or $invalid, optional
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -421,7 +449,8 @@ export default
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add a permission',
|
awToolTip: 'Add a permission',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(credential_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,16 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
tab: 'properties'
|
tab: 'properties',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
tab: 'properties'
|
tab: 'properties',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
variables: {
|
variables: {
|
||||||
label: 'Variables',
|
label: 'Variables',
|
||||||
@@ -65,7 +67,8 @@ export default
|
|||||||
ngChange: 'sourceChange(source)',
|
ngChange: 'sourceChange(source)',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
ngModel: 'source'
|
ngModel: 'source',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
credential: {
|
credential: {
|
||||||
label: 'Cloud Credential',
|
label: 'Cloud Credential',
|
||||||
@@ -77,7 +80,8 @@ export default
|
|||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "cloudCredentialRequired",
|
reqExpression: "cloudCredentialRequired",
|
||||||
init: "false"
|
init: "false"
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
source_regions: {
|
source_regions: {
|
||||||
label: 'Regions',
|
label: 'Regions',
|
||||||
@@ -92,7 +96,8 @@ export default
|
|||||||
awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " +
|
awPopOver: "<p>Click on the regions field to see a list of regions for your cloud provider. You can select multiple regions, " +
|
||||||
"or choose <em>All</em> to include all regions. Tower will only be updated with Hosts associated with the selected regions." +
|
"or choose <em>All</em> to include all regions. Tower will only be updated with Hosts associated with the selected regions." +
|
||||||
"</p>",
|
"</p>",
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
instance_filters: {
|
instance_filters: {
|
||||||
label: 'Instance Filters',
|
label: 'Instance Filters',
|
||||||
@@ -112,7 +117,8 @@ export default
|
|||||||
"<blockquote>tag:Name=test*</blockquote>\n" +
|
"<blockquote>tag:Name=test*</blockquote>\n" +
|
||||||
"<p>View the <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html\" target=\"_blank\">Describe Instances documentation</a> " +
|
"<p>View the <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html\" target=\"_blank\">Describe Instances documentation</a> " +
|
||||||
"for a complete list of supported filters.</p>",
|
"for a complete list of supported filters.</p>",
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
group_by: {
|
group_by: {
|
||||||
label: 'Only Group By',
|
label: 'Only Group By',
|
||||||
@@ -137,7 +143,8 @@ export default
|
|||||||
"<li>VPC ID: <strong>vpcs » vpc-5ca1ab1e</strong></li>" +
|
"<li>VPC ID: <strong>vpcs » vpc-5ca1ab1e</strong></li>" +
|
||||||
"<li>Tag None: <strong>tags » tag_none</strong></li>" +
|
"<li>Tag None: <strong>tags » tag_none</strong></li>" +
|
||||||
"</ul><p>If blank, all groups above are created except <em>Instance ID</em>.</p>",
|
"</ul><p>If blank, all groups above are created except <em>Instance ID</em>.</p>",
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
inventory_script: {
|
inventory_script: {
|
||||||
label : "Custom Inventory Script",
|
label : "Custom Inventory Script",
|
||||||
@@ -149,6 +156,7 @@ export default
|
|||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
ngRequired: "source && source.value === 'custom'",
|
ngRequired: "source && source.value === 'custom'",
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||||
},
|
},
|
||||||
custom_variables: {
|
custom_variables: {
|
||||||
id: 'custom_variables',
|
id: 'custom_variables',
|
||||||
@@ -269,7 +277,8 @@ export default
|
|||||||
dataTitle: 'Overwrite',
|
dataTitle: 'Overwrite',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options'
|
labelClass: 'checkbox-options',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'overwrite_vars',
|
name: 'overwrite_vars',
|
||||||
label: 'Overwrite Variables',
|
label: 'Overwrite Variables',
|
||||||
@@ -283,7 +292,8 @@ export default
|
|||||||
dataTitle: 'Overwrite Variables',
|
dataTitle: 'Overwrite Variables',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options'
|
labelClass: 'checkbox-options',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'update_on_launch',
|
name: 'update_on_launch',
|
||||||
label: 'Update on Launch',
|
label: 'Update on Launch',
|
||||||
@@ -296,7 +306,8 @@ export default
|
|||||||
dataTitle: 'Update on Launch',
|
dataTitle: 'Update on Launch',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options'
|
labelClass: 'checkbox-options',
|
||||||
|
ngDisabled: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
update_cache_timeout: {
|
update_cache_timeout: {
|
||||||
@@ -321,11 +332,17 @@ export default
|
|||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(group_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -46,13 +46,15 @@ export default
|
|||||||
"</blockquote>",
|
"</blockquote>",
|
||||||
dataTitle: 'Host Name',
|
dataTitle: 'Host Name',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
variables: {
|
variables: {
|
||||||
label: 'Variables',
|
label: 'Variables',
|
||||||
@@ -83,10 +85,16 @@ export default
|
|||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()',
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(host.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,16 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
inventory_description: {
|
inventory_description: {
|
||||||
realName: 'description',
|
realName: 'description',
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -44,7 +46,8 @@ export default
|
|||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "organizationrequired",
|
reqExpression: "organizationrequired",
|
||||||
init: "true"
|
init: "true"
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
variables: {
|
variables: {
|
||||||
label: 'Variables',
|
label: 'Variables',
|
||||||
@@ -63,17 +66,24 @@ export default
|
|||||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||||
dataTitle: 'Inventory Variables',
|
dataTitle: 'Inventory Variables',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(inventory_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngHide: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -94,7 +104,8 @@ export default
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add a permission',
|
awToolTip: 'Add a permission',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(inventory_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,16 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
column: 1
|
column: 1,
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
column: 1
|
column: 1,
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
job_type: {
|
job_type: {
|
||||||
label: 'Job Type',
|
label: 'Job Type',
|
||||||
@@ -56,7 +58,8 @@ export default
|
|||||||
variable: 'ask_job_type_on_launch',
|
variable: 'ask_job_type_on_launch',
|
||||||
ngShow: "!job_type.value || job_type.value !== 'scan'",
|
ngShow: "!job_type.value || job_type.value !== 'scan'",
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
inventory: {
|
inventory: {
|
||||||
label: 'Inventory',
|
label: 'Inventory',
|
||||||
@@ -78,7 +81,8 @@ export default
|
|||||||
variable: 'ask_inventory_on_launch',
|
variable: 'ask_inventory_on_launch',
|
||||||
ngShow: "!job_type.value || job_type.value !== 'scan'",
|
ngShow: "!job_type.value || job_type.value !== 'scan'",
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
project: {
|
project: {
|
||||||
label: 'Project',
|
label: 'Project',
|
||||||
@@ -100,12 +104,13 @@ export default
|
|||||||
dataTitle: 'Project',
|
dataTitle: 'Project',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
playbook: {
|
playbook: {
|
||||||
label: 'Playbook',
|
label: 'Playbook',
|
||||||
type:'select',
|
type:'select',
|
||||||
ngOptions: 'book for book in playbook_options track by book',
|
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') || !(job_template_obj.summary_fields.user_capabilities.edit || canAdd)",
|
||||||
id: 'playbook-select',
|
id: 'playbook-select',
|
||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "playbookrequired",
|
reqExpression: "playbookrequired",
|
||||||
@@ -138,7 +143,8 @@ export default
|
|||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ask_credential_on_launch',
|
variable: 'ask_credential_on_launch',
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
cloud_credential: {
|
cloud_credential: {
|
||||||
label: '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.</p>",
|
"running playbook, allowing provisioning into the cloud without manually passing parameters to the included modules.</p>",
|
||||||
dataTitle: 'Cloud Credential',
|
dataTitle: 'Cloud Credential',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
network_credential: {
|
network_credential: {
|
||||||
label: 'Network Credential',
|
label: 'Network Credential',
|
||||||
@@ -167,7 +174,8 @@ export default
|
|||||||
awPopOver: "<p>Network credentials are used by Ansible networking modules to connect to and manage networking devices.</p>",
|
awPopOver: "<p>Network credentials are used by Ansible networking modules to connect to and manage networking devices.</p>",
|
||||||
dataTitle: 'Network Credential',
|
dataTitle: 'Network Credential',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
forks: {
|
forks: {
|
||||||
label: 'Forks',
|
label: 'Forks',
|
||||||
@@ -186,7 +194,8 @@ export default
|
|||||||
' target=\"_blank\">ansible configuration file</a>.</p>',
|
' target=\"_blank\">ansible configuration file</a>.</p>',
|
||||||
dataTitle: 'Forks',
|
dataTitle: 'Forks',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working
|
||||||
},
|
},
|
||||||
limit: {
|
limit: {
|
||||||
label: 'Limit',
|
label: 'Limit',
|
||||||
@@ -203,7 +212,8 @@ export default
|
|||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ask_limit_on_launch',
|
variable: 'ask_limit_on_launch',
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
verbosity: {
|
verbosity: {
|
||||||
label: 'Verbosity',
|
label: 'Verbosity',
|
||||||
@@ -216,7 +226,8 @@ export default
|
|||||||
awPopOver: "<p>Control the level of output ansible will produce as the playbook executes.</p>",
|
awPopOver: "<p>Control the level of output ansible will produce as the playbook executes.</p>",
|
||||||
dataTitle: 'Verbosity',
|
dataTitle: 'Verbosity',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
job_tags: {
|
job_tags: {
|
||||||
label: 'Job Tags',
|
label: 'Job Tags',
|
||||||
@@ -235,7 +246,8 @@ export default
|
|||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ask_tags_on_launch',
|
variable: 'ask_tags_on_launch',
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
skip_tags: {
|
skip_tags: {
|
||||||
label: 'Skip Tags',
|
label: 'Skip Tags',
|
||||||
@@ -254,7 +266,8 @@ export default
|
|||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ask_skip_tags_on_launch',
|
variable: 'ask_skip_tags_on_launch',
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
checkbox_group: {
|
checkbox_group: {
|
||||||
label: 'Options',
|
label: 'Options',
|
||||||
@@ -270,7 +283,8 @@ export default
|
|||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataTitle: 'Become Privilege Escalation',
|
dataTitle: 'Become Privilege Escalation',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
labelClass: 'stack-inline'
|
labelClass: 'stack-inline',
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'allow_callbacks',
|
name: 'allow_callbacks',
|
||||||
label: 'Allow Provisioning Callbacks',
|
label: 'Allow Provisioning Callbacks',
|
||||||
@@ -284,7 +298,8 @@ export default
|
|||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataTitle: 'Allow Provisioning Callbacks',
|
dataTitle: 'Allow Provisioning Callbacks',
|
||||||
dataContainer: "body",
|
dataContainer: "body",
|
||||||
labelClass: 'stack-inline'
|
labelClass: 'stack-inline',
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
callback_url: {
|
callback_url: {
|
||||||
@@ -299,7 +314,8 @@ export default
|
|||||||
awPopOverWatch: "callback_help",
|
awPopOverWatch: "callback_help",
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
dataTitle: 'Provisioning Callback URL',
|
dataTitle: 'Provisioning Callback URL',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
host_config_key: {
|
host_config_key: {
|
||||||
label: 'Host Config Key',
|
label: 'Host Config Key',
|
||||||
@@ -312,7 +328,8 @@ export default
|
|||||||
awPopOverWatch: "callback_help",
|
awPopOverWatch: "callback_help",
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataTitle: "Host Config Key",
|
dataTitle: "Host Config Key",
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
label: 'Labels',
|
label: 'Labels',
|
||||||
@@ -325,7 +342,8 @@ export default
|
|||||||
dataTitle: 'Labels',
|
dataTitle: 'Labels',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
awPopOver: "<p>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.</p>",
|
awPopOver: "<p>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.</p>",
|
||||||
dataContainer: 'body'
|
dataContainer: 'body',
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
variables: {
|
variables: {
|
||||||
label: 'Extra Variables',
|
label: 'Extra Variables',
|
||||||
@@ -348,14 +366,15 @@ export default
|
|||||||
subCheckbox: {
|
subCheckbox: {
|
||||||
variable: 'ask_variables_on_launch',
|
variable: 'ask_variables_on_launch',
|
||||||
text: 'Prompt on launch'
|
text: 'Prompt on launch'
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: { //for now always generates <button> tags
|
buttons: { //for now always generates <button> tags
|
||||||
add_survey: {
|
add_survey: {
|
||||||
ngClick: 'addSurvey()',
|
ngClick: 'addSurvey()',
|
||||||
ngShow: 'job_type.value !== "scan" && !survey_exists',
|
ngShow: 'job_type.value !== "scan" && !survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||||
awFeature: 'surveys',
|
awFeature: 'surveys',
|
||||||
awToolTip: 'Surveys allow users to be prompted at job launch with a series of questions related to the job. This allows for variables to be defined that affect the playbook run at time of launch.',
|
awToolTip: 'Surveys allow users to be prompted at job launch with a series of questions related to the job. This allows for variables to be defined that affect the playbook run at time of launch.',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top'
|
||||||
@@ -363,14 +382,25 @@ export default
|
|||||||
edit_survey: {
|
edit_survey: {
|
||||||
ngClick: 'editSurvey()',
|
ngClick: 'editSurvey()',
|
||||||
awFeature: 'surveys',
|
awFeature: 'surveys',
|
||||||
ngShow: 'job_type.value !== "scan" && survey_exists'
|
ngShow: 'job_type.value !== "scan" && survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
view_survey: {
|
||||||
|
ngClick: 'editSurvey()',
|
||||||
|
awFeature: 'surveys',
|
||||||
|
ngShow: 'job_type.value !== "scan" && survey_exists && !(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||||
ngDisabled: "job_templates_form.$invalid || can_edit!==true"//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
|
ngDisabled: "job_templates_form.$invalid",//true //Disable when $pristine or $invalid, optional and when can_edit = false, for permission reasons
|
||||||
|
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -394,7 +424,8 @@ export default
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add a permission',
|
awToolTip: 'Add a permission',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(job_template_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -25,23 +25,31 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: { //for now always generates <button> tags
|
buttons: { //for now always generates <button> tags
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
ngDisabled: true,
|
||||||
|
ngShow: '(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -62,7 +70,8 @@ export default
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add a permission',
|
awToolTip: 'Add a permission',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(organization_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,15 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -50,7 +52,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
},
|
},
|
||||||
dataTitle: 'Organization',
|
dataTitle: 'Organization',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right'
|
dataPlacement: 'right',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
scm_type: {
|
scm_type: {
|
||||||
label: 'SCM Type',
|
label: 'SCM Type',
|
||||||
@@ -61,6 +64,7 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
hasSubForm: true,
|
hasSubForm: true,
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
missing_path_alert: {
|
missing_path_alert: {
|
||||||
type: 'alertblock',
|
type: 'alertblock',
|
||||||
@@ -82,7 +86,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||||
dataTitle: 'Project Base Path',
|
dataTitle: 'Project Base Path',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right'
|
dataPlacement: 'right',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
local_path: {
|
local_path: {
|
||||||
label: 'Playbook Directory',
|
label: 'Playbook Directory',
|
||||||
@@ -99,7 +104,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||||
dataTitle: 'Project Path',
|
dataTitle: 'Project Path',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right'
|
dataPlacement: 'right',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
scm_url: {
|
scm_url: {
|
||||||
label: 'SCM URL',
|
label: 'SCM URL',
|
||||||
@@ -115,7 +121,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
awPopOver: "set in controllers/projects",
|
awPopOver: "set in controllers/projects",
|
||||||
dataTitle: 'SCM URL',
|
dataTitle: 'SCM URL',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right'
|
dataPlacement: 'right',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
scm_branch: {
|
scm_branch: {
|
||||||
labelBind: "scmBranchLabel",
|
labelBind: "scmBranchLabel",
|
||||||
@@ -123,7 +130,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
ngShow: "scm_type && scm_type.value !== 'manual'",
|
ngShow: "scm_type && scm_type.value !== 'manual'",
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subForm: 'sourceSubForm'
|
subForm: 'sourceSubForm',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
credential: {
|
credential: {
|
||||||
label: 'SCM Credential',
|
label: 'SCM Credential',
|
||||||
@@ -134,7 +142,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
ngClick: 'lookUpCredential()',
|
ngClick: 'lookUpCredential()',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false,
|
editRequired: false,
|
||||||
subForm: 'sourceSubForm'
|
subForm: 'sourceSubForm',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
checkbox_group: {
|
checkbox_group: {
|
||||||
label: 'SCM Update Options',
|
label: 'SCM Update Options',
|
||||||
@@ -151,7 +160,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
dataTitle: 'SCM Clean',
|
dataTitle: 'SCM Clean',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options stack-inline'
|
labelClass: 'checkbox-options stack-inline',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'scm_delete_on_update',
|
name: 'scm_delete_on_update',
|
||||||
label: 'Delete on Update',
|
label: 'Delete on Update',
|
||||||
@@ -163,7 +173,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
dataTitle: 'SCM Delete',
|
dataTitle: 'SCM Delete',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options stack-inline'
|
labelClass: 'checkbox-options stack-inline',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'scm_update_on_launch',
|
name: 'scm_update_on_launch',
|
||||||
label: 'Update on Launch',
|
label: 'Update on Launch',
|
||||||
@@ -174,7 +185,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
dataTitle: 'SCM Update',
|
dataTitle: 'SCM Update',
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
labelClass: 'checkbox-options stack-inline'
|
labelClass: 'checkbox-options stack-inline',
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
scm_update_cache_timeout: {
|
scm_update_cache_timeout: {
|
||||||
@@ -193,17 +205,24 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
'and a new project update will be performed.</p>',
|
'and a new project update will be performed.</p>',
|
||||||
dataTitle: 'Cache Timeout',
|
dataTitle: 'Cache Timeout',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
dataContainer: "body"
|
dataContainer: "body",
|
||||||
|
ngDisabled: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)' // TODO: get working
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -224,7 +243,8 @@ angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add a permission',
|
awToolTip: 'Add a permission',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(project_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,15 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -44,17 +46,24 @@ export default
|
|||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "orgrequired",
|
reqExpression: "orgrequired",
|
||||||
init: true
|
init: true
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -75,7 +84,8 @@ export default
|
|||||||
label: 'Add',
|
label: 'Add',
|
||||||
awToolTip: 'Add user to team',
|
awToolTip: 'Add user to team',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: '(team_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,7 +142,8 @@ export default
|
|||||||
'class': "List-actionButton--delete",
|
'class': "List-actionButton--delete",
|
||||||
iconClass: 'fa fa-times',
|
iconClass: 'fa fa-times',
|
||||||
awToolTip: 'Dissasociate permission from team',
|
awToolTip: 'Dissasociate permission from team',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'permission.summary_fields.user_capabilities.unattach'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hideOnSuperuser: true
|
hideOnSuperuser: true
|
||||||
|
|||||||
@@ -26,21 +26,24 @@ export default
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: true
|
capitalize: true,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
last_name: {
|
last_name: {
|
||||||
label: 'Last Name',
|
label: 'Last Name',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: true
|
capitalize: true,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
label: 'Email',
|
label: 'Email',
|
||||||
type: 'email',
|
type: 'email',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
autocomplete: false
|
autocomplete: false,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
label: 'Username',
|
label: 'Username',
|
||||||
@@ -49,7 +52,8 @@ export default
|
|||||||
reqExpression: "not_ldap_user && external_account === null",
|
reqExpression: "not_ldap_user && external_account === null",
|
||||||
init: true
|
init: true
|
||||||
},
|
},
|
||||||
autocomplete: false
|
autocomplete: false,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -63,7 +67,8 @@ export default
|
|||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "orgrequired",
|
reqExpression: "orgrequired",
|
||||||
init: true
|
init: true
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
label: 'Password',
|
label: 'Password',
|
||||||
@@ -74,7 +79,8 @@ export default
|
|||||||
editRequired: false,
|
editRequired: false,
|
||||||
ngChange: "clearPWConfirm('password_confirm')",
|
ngChange: "clearPWConfirm('password_confirm')",
|
||||||
autocomplete: false,
|
autocomplete: false,
|
||||||
chkPass: true
|
chkPass: true,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
password_confirm: {
|
password_confirm: {
|
||||||
label: 'Confirm Password',
|
label: 'Confirm Password',
|
||||||
@@ -85,7 +91,8 @@ export default
|
|||||||
editRequired: false,
|
editRequired: false,
|
||||||
awPassMatch: true,
|
awPassMatch: true,
|
||||||
associated: 'password',
|
associated: 'password',
|
||||||
autocomplete: false
|
autocomplete: false,
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
user_type: {
|
user_type: {
|
||||||
label: 'User Type',
|
label: 'User Type',
|
||||||
@@ -94,16 +101,23 @@ export default
|
|||||||
disableChooseOption: true,
|
disableChooseOption: true,
|
||||||
ngModel: 'user_type',
|
ngModel: 'user_type',
|
||||||
ngShow: 'current_user["is_superuser"]',
|
ngShow: 'current_user["is_superuser"]',
|
||||||
|
ngDisabled: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()'
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()',
|
ngClick: 'formSave()',
|
||||||
ngDisabled: true
|
ngDisabled: true,
|
||||||
|
ngShow: '(user_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -186,7 +200,8 @@ export default
|
|||||||
label: 'Remove',
|
label: 'Remove',
|
||||||
ngClick: 'deletePermissionFromUser(user_id, username, permission.name, permission.summary_fields.resource_name, permission.related.users)',
|
ngClick: 'deletePermissionFromUser(user_id, username, permission.name, permission.summary_fields.resource_name, permission.related.users)',
|
||||||
iconClass: 'fa fa-times',
|
iconClass: 'fa fa-times',
|
||||||
awToolTip: 'Dissasociate permission from user'
|
awToolTip: 'Dissasociate permission from user',
|
||||||
|
ngShow: 'permission.summary_fields.user_capabilities.unattach'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hideOnSuperuser: true
|
hideOnSuperuser: true
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default
|
|||||||
function createField(onChange, onReady, fld) {
|
function createField(onChange, onReady, fld) {
|
||||||
//hide the textarea and show a fresh CodeMirror with the current mode (json or yaml)
|
//hide the textarea and show a fresh CodeMirror with the current mode (json or yaml)
|
||||||
|
|
||||||
scope[fld + 'codeMirror'] = AngularCodeMirror();
|
scope[fld + 'codeMirror'] = AngularCodeMirror(readOnly);
|
||||||
scope[fld + 'codeMirror'].addModes(global.$AnsibleConfig.variable_edit_modes);
|
scope[fld + 'codeMirror'].addModes(global.$AnsibleConfig.variable_edit_modes);
|
||||||
scope[fld + 'codeMirror'].showTextArea({
|
scope[fld + 'codeMirror'].showTextArea({
|
||||||
scope: scope,
|
scope: scope,
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ export default
|
|||||||
Rest.get()
|
Rest.get()
|
||||||
.success(function (data) {
|
.success(function (data) {
|
||||||
var opts = [], i;
|
var opts = [], i;
|
||||||
for (i = 0; i < data.project_local_paths.length; i++) {
|
if (data.project_local_paths) {
|
||||||
opts.push({
|
for (i = 0; i < data.project_local_paths.length; i++) {
|
||||||
label: data.project_local_paths[i],
|
opts.push({
|
||||||
value: data.project_local_paths[i]
|
label: data.project_local_paths[i],
|
||||||
});
|
value: data.project_local_paths[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (scope.local_path) {
|
if (scope.local_path) {
|
||||||
// List only includes paths not assigned to projects, so add the
|
// List only includes paths not assigned to projects, so add the
|
||||||
|
|||||||
@@ -16,6 +16,15 @@ function InventoriesAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
PaginateInit, LookUpInit, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
PaginateInit, LookUpInit, GetBasePath, ParseTypeChange, Wait, ToJSON,
|
||||||
$state) {
|
$state) {
|
||||||
|
|
||||||
|
Rest.setUrl(GetBasePath('inventory'));
|
||||||
|
Rest.options()
|
||||||
|
.success(function(data) {
|
||||||
|
if (!data.actions.POST) {
|
||||||
|
$state.go("^");
|
||||||
|
Alert('Permission Error', 'You do not have permission to add an inventory.', 'alert-info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ function InventoriesEdit($scope, $rootScope, $compile, $location,
|
|||||||
ParseVariableString, RelatedSearchInit, RelatedPaginateInit,
|
ParseVariableString, RelatedSearchInit, RelatedPaginateInit,
|
||||||
Prompt, InitiatePlaybookRun, CreateDialog, deleteJobTemplate, $state,
|
Prompt, InitiatePlaybookRun, CreateDialog, deleteJobTemplate, $state,
|
||||||
$filter) {
|
$filter) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
@@ -32,6 +31,13 @@ function InventoriesEdit($scope, $rootScope, $compile, $location,
|
|||||||
form.formLabelSize = null;
|
form.formLabelSize = null;
|
||||||
form.formFieldSize = null;
|
form.formFieldSize = null;
|
||||||
$scope.inventory_id = inventory_id;
|
$scope.inventory_id = inventory_id;
|
||||||
|
|
||||||
|
$scope.$watch('invnentory_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
generator.inject(form, { mode: 'edit', related: true, scope: $scope });
|
||||||
|
|
||||||
generator.reset();
|
generator.reset();
|
||||||
|
|||||||
@@ -14,7 +14,14 @@ function InventoriesList($scope, $rootScope, $location, $log,
|
|||||||
$stateParams, $compile, $filter, sanitizeFilter, Rest, Alert, InventoryList,
|
$stateParams, $compile, $filter, sanitizeFilter, Rest, Alert, InventoryList,
|
||||||
generateList, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
generateList, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||||
ClearScope, ProcessErrors, GetBasePath, Wait,
|
ClearScope, ProcessErrors, GetBasePath, Wait,
|
||||||
Find, Empty, $state) {
|
Find, Empty, $state, rbacUiControlService) {
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd('inventory')
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
var list = InventoryList,
|
var list = InventoryList,
|
||||||
defaultUrl = GetBasePath('inventory') + ($stateParams.status === 'sync-failed' ? '?not__inventory_sources_with_failures=0' : ''),
|
defaultUrl = GetBasePath('inventory') + ($stateParams.status === 'sync-failed' ? '?not__inventory_sources_with_failures=0' : ''),
|
||||||
@@ -376,4 +383,4 @@ function InventoriesList($scope, $rootScope, $location, $log,
|
|||||||
export default ['$scope', '$rootScope', '$location', '$log',
|
export default ['$scope', '$rootScope', '$location', '$log',
|
||||||
'$stateParams', '$compile', '$filter', 'sanitizeFilter', 'Rest', 'Alert', 'InventoryList',
|
'$stateParams', '$compile', '$filter', 'sanitizeFilter', 'Rest', 'Alert', 'InventoryList',
|
||||||
'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller',
|
'generateList', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller',
|
||||||
'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', InventoriesList];
|
'ClearScope', 'ProcessErrors', 'GetBasePath', 'Wait', 'Find', 'Empty', '$state', 'rbacUiControlService', InventoriesList];
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
export default
|
export default
|
||||||
['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'LookUpInit',
|
['$state', '$stateParams', '$scope', 'GroupForm', 'CredentialList', 'inventoryScriptsListObject', 'ParseTypeChange', 'GenerateForm', 'inventoryData', 'LookUpInit',
|
||||||
'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions',
|
'GroupManageService', 'GetChoices', 'GetBasePath', 'CreateSelect2', 'GetSourceTypeOptions', 'rbacUiControlService',
|
||||||
function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ParseTypeChange, GenerateForm, inventoryData, LookUpInit,
|
function($state, $stateParams, $scope, GroupForm, CredentialList, InventoryScriptsList, ParseTypeChange, GenerateForm, inventoryData, LookUpInit,
|
||||||
GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions){
|
GroupManageService, GetChoices, GetBasePath, CreateSelect2, GetSourceTypeOptions, rbacUiControlService){
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
form = GroupForm();
|
form = GroupForm();
|
||||||
|
|
||||||
@@ -16,6 +16,11 @@
|
|||||||
CredentialList = _.cloneDeep(CredentialList);
|
CredentialList = _.cloneDeep(CredentialList);
|
||||||
CredentialList.fields.kind.noSearch = true;
|
CredentialList.fields.kind.noSearch = true;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/groups")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^');
|
$state.go('^');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
CredentialList = _.cloneDeep(CredentialList);
|
CredentialList = _.cloneDeep(CredentialList);
|
||||||
CredentialList.fields.kind.noSearch = true;
|
CredentialList.fields.kind.noSearch = true;
|
||||||
|
|
||||||
|
$scope.$watch('group_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^');
|
$state.go('^');
|
||||||
};
|
};
|
||||||
@@ -256,6 +262,7 @@
|
|||||||
$scope.credential_name = inventorySourceData.summary_fields.credential.name;
|
$scope.credential_name = inventorySourceData.summary_fields.credential.name;
|
||||||
}
|
}
|
||||||
$scope = angular.extend($scope, groupData);
|
$scope = angular.extend($scope, groupData);
|
||||||
|
$scope.group_obj = groupData;
|
||||||
|
|
||||||
// instantiate lookup fields
|
// instantiate lookup fields
|
||||||
if (inventorySourceData.source !== 'custom'){
|
if (inventorySourceData.source !== 'custom'){
|
||||||
|
|||||||
@@ -5,13 +5,22 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
export default
|
export default
|
||||||
['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus',
|
['$scope', '$rootScope', '$state', '$stateParams', 'InventoryGroups', 'generateList', 'InventoryUpdate', 'GroupManageService', 'GroupsCancelUpdate', 'ViewUpdateStatus',
|
||||||
'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
|
'InventoryManageService', 'groupsUrl', 'SearchInit', 'PaginateInit', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Rest', 'GetBasePath', 'rbacUiControlService',
|
||||||
function($scope, $rootScope, $state, $stateParams, InventoryGroups, generateList, InventoryUpdate, GroupManageService, GroupsCancelUpdate, ViewUpdateStatus,
|
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, rbacUiControlService){
|
||||||
var list = InventoryGroups,
|
var list = InventoryGroups,
|
||||||
view = generateList,
|
view = generateList,
|
||||||
pageSize = 20;
|
pageSize = 20;
|
||||||
$scope.inventory_id = $stateParams.inventory_id;
|
$scope.inventory_id = $stateParams.inventory_id;
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd(GetBasePath('inventory') + $scope.inventory_id + "/groups")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// The ncy breadcrumb directive will look at this attribute when attempting to bind to the correct scope.
|
// 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:
|
// 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
|
// https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the
|
||||||
|
|||||||
@@ -5,10 +5,18 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService',
|
['$state', '$stateParams', '$scope', 'HostForm', 'ParseTypeChange', 'GenerateForm', 'HostManageService', 'rbacUiControlService', 'GetBasePath',
|
||||||
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService){
|
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, rbacUiControlService, GetBasePath){
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
form = HostForm;
|
form = HostForm;
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd(GetBasePath('inventory') + $stateParams.inventory_id + "/hosts")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
$scope.parseType = 'yaml';
|
$scope.parseType = 'yaml';
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^');
|
$state.go('^');
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){
|
function($state, $stateParams, $scope, HostForm, ParseTypeChange, GenerateForm, HostManageService, host){
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
form = HostForm;
|
form = HostForm;
|
||||||
|
|
||||||
|
$scope.$watch('host.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$scope.parseType = 'yaml';
|
$scope.parseType = 'yaml';
|
||||||
$scope.formCancel = function(){
|
$scope.formCancel = function(){
|
||||||
$state.go('^');
|
$state.go('^');
|
||||||
|
|||||||
@@ -5,12 +5,23 @@
|
|||||||
*************************************************/
|
*************************************************/
|
||||||
export default
|
export default
|
||||||
['$scope', '$rootScope', '$state', '$stateParams', 'InventoryHosts', 'generateList', 'InventoryManageService', 'HostManageService',
|
['$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', 'rbacUiControlService',
|
||||||
function($scope, $rootScope, $state, $stateParams, InventoryHosts, generateList, InventoryManageService, HostManageService,
|
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, rbacUiControlService){
|
||||||
|
|
||||||
var list = InventoryHosts,
|
var list = InventoryHosts,
|
||||||
view = generateList,
|
view = generateList,
|
||||||
pageSize = 20;
|
pageSize = 20;
|
||||||
|
|
||||||
|
$scope.inventory_id = $stateParams.inventory_id;
|
||||||
|
|
||||||
|
$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.
|
// 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:
|
// 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
|
// https://github.com/ncuillery/angular-breadcrumb/issues/42 for a little more information on the
|
||||||
|
|||||||
@@ -3,21 +3,26 @@
|
|||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
export default
|
export default
|
||||||
['$scope', '$state', function($scope, $state){
|
['$scope', '$state', 'inventoryData', function($scope, $state, inventoryData){
|
||||||
$scope.groupsSelected = false;
|
$scope.groupsSelected = false;
|
||||||
$scope.hostsSelected = false;
|
$scope.hostsSelected = false;
|
||||||
$scope.hostsSelectedItems = [];
|
$scope.hostsSelectedItems = [];
|
||||||
$scope.groupsSelectedItems = [];
|
$scope.groupsSelectedItems = [];
|
||||||
$scope.setAdhocPattern = function(){
|
|
||||||
var pattern = _($scope.groupsSelectedItems)
|
$scope.canAdhoc = inventoryData.summary_fields.user_capabilities.adhoc;
|
||||||
.concat($scope.hostsSelectedItems)
|
|
||||||
.map(function(item){
|
$scope.setAdhocPattern = function(){
|
||||||
return item.name;
|
var pattern = _($scope.groupsSelectedItems)
|
||||||
}).value().join(':');
|
.concat($scope.hostsSelectedItems)
|
||||||
$state.go('inventoryManage.adhoc', {pattern: pattern});
|
.map(function(item){
|
||||||
};
|
return item.name;
|
||||||
|
}).value().join(':');
|
||||||
|
|
||||||
|
$state.go('inventoryManage.adhoc', {pattern: pattern});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.$watchGroup(['groupsSelected', 'hostsSelected'], function(newVals) {
|
$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.";
|
$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.";
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -8,20 +8,27 @@ export default
|
|||||||
[ '$rootScope', 'pagination', '$compile','SchedulerInit', 'Rest', 'Wait',
|
[ '$rootScope', 'pagination', '$compile','SchedulerInit', 'Rest', 'Wait',
|
||||||
'inventoryScriptsFormObject', 'ProcessErrors', 'GetBasePath', 'Empty',
|
'inventoryScriptsFormObject', 'ProcessErrors', 'GetBasePath', 'Empty',
|
||||||
'GenerateForm', 'SearchInit' , 'PaginateInit',
|
'GenerateForm', 'SearchInit' , 'PaginateInit',
|
||||||
'LookUpInit', 'OrganizationList', '$scope', '$state',
|
'LookUpInit', 'OrganizationList', '$scope', '$state', 'Alert',
|
||||||
function(
|
function(
|
||||||
$rootScope, pagination, $compile, SchedulerInit, Rest, Wait,
|
$rootScope, pagination, $compile, SchedulerInit, Rest, Wait,
|
||||||
inventoryScriptsFormObject, ProcessErrors, GetBasePath, Empty,
|
inventoryScriptsFormObject, ProcessErrors, GetBasePath, Empty,
|
||||||
GenerateForm, SearchInit, PaginateInit,
|
GenerateForm, SearchInit, PaginateInit,
|
||||||
LookUpInit, OrganizationList, $scope, $state
|
LookUpInit, OrganizationList, $scope, $state, Alert
|
||||||
) {
|
) {
|
||||||
|
Rest.setUrl(GetBasePath('inventory_scripts'));
|
||||||
|
Rest.options()
|
||||||
|
.success(function(data) {
|
||||||
|
if (!data.actions.POST) {
|
||||||
|
$state.go("^");
|
||||||
|
Alert('Permission Error', 'You do not have permission to add an inventory script.', 'alert-info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var scope = $scope,
|
var scope = $scope,
|
||||||
generator = GenerateForm,
|
generator = GenerateForm,
|
||||||
form = inventoryScriptsFormObject,
|
form = inventoryScriptsFormObject,
|
||||||
url = GetBasePath('inventory_scripts');
|
url = GetBasePath('inventory_scripts');
|
||||||
|
|
||||||
$scope.canEdit = true;
|
|
||||||
|
|
||||||
generator.inject(form, {
|
generator.inject(form, {
|
||||||
mode: 'add' ,
|
mode: 'add' ,
|
||||||
scope:scope,
|
scope:scope,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export default
|
|||||||
LookUpInit, OrganizationList, inventory_script,
|
LookUpInit, OrganizationList, inventory_script,
|
||||||
$scope, $state
|
$scope, $state
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var generator = GenerateForm,
|
var generator = GenerateForm,
|
||||||
id = inventory_script.id,
|
id = inventory_script.id,
|
||||||
form = inventoryScriptsFormObject,
|
form = inventoryScriptsFormObject,
|
||||||
@@ -24,6 +25,13 @@ export default
|
|||||||
url = GetBasePath('inventory_scripts');
|
url = GetBasePath('inventory_scripts');
|
||||||
|
|
||||||
$scope.inventory_script = inventory_script;
|
$scope.inventory_script = inventory_script;
|
||||||
|
|
||||||
|
$scope.$watch('inventory_script_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
generator.inject(form, {
|
generator.inject(form, {
|
||||||
mode: 'edit' ,
|
mode: 'edit' ,
|
||||||
scope:$scope,
|
scope:$scope,
|
||||||
|
|||||||
@@ -24,13 +24,15 @@ export default function() {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -41,7 +43,8 @@ export default function() {
|
|||||||
},
|
},
|
||||||
sourceModel: 'organization',
|
sourceModel: 'organization',
|
||||||
sourceField: 'name',
|
sourceField: 'name',
|
||||||
ngClick: 'lookUpOrganization()'
|
ngClick: 'lookUpOrganization()',
|
||||||
|
ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
script: {
|
script: {
|
||||||
label: 'Custom Script',
|
label: 'Custom Script',
|
||||||
@@ -51,7 +54,7 @@ export default function() {
|
|||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
awDropFile: true,
|
awDropFile: true,
|
||||||
ngDisabled: '!canEdit',
|
ngDisabled: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)',
|
||||||
rows: 10,
|
rows: 10,
|
||||||
awPopOver: "<p>Drag and drop your custom inventory script file here or create one in the field to import your custom inventory. " +
|
awPopOver: "<p>Drag and drop your custom inventory script file here or create one in the field to import your custom inventory. " +
|
||||||
"<br><br> Script must begin with a hashbang sequence: i.e.... #!/usr/bin/env python</p>",
|
"<br><br> Script must begin with a hashbang sequence: i.e.... #!/usr/bin/env python</p>",
|
||||||
@@ -64,10 +67,16 @@ export default function() {
|
|||||||
buttons: { //for now always generates <button> tags
|
buttons: { //for now always generates <button> tags
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()',
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||||
ngDisabled: 'custom_inventory_form.$pristine || custom_inventory_form.$invalid || !canEdit' //Disable when $pristine or $invalid, optional
|
ngDisabled: 'custom_inventory_form.$pristine || custom_inventory_form.$invalid', //Disable when $pristine or $invalid, optional
|
||||||
|
ngShow: '(inventory_script_obj.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ export default function(){
|
|||||||
ngClick: 'addCustomInv()',
|
ngClick: 'addCustomInv()',
|
||||||
awToolTip: 'Create a new custom inventory',
|
awToolTip: 'Create a new custom inventory',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -56,7 +57,16 @@ export default function(){
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Edit inventory script',
|
awToolTip: 'Edit inventory script',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'inventory_script.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
ngClick: "editCustomInv(inventory_script.id)",
|
||||||
|
label: 'View',
|
||||||
|
"class": 'btn-sm',
|
||||||
|
awToolTip: 'View inventory script',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!inventory_script.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
ngClick: "deleteCustomInv(inventory_script.id, inventory_script.name)",
|
ngClick: "deleteCustomInv(inventory_script.id, inventory_script.name)",
|
||||||
@@ -64,7 +74,8 @@ export default function(){
|
|||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Delete inventory script',
|
awToolTip: 'Delete inventory script',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'inventory_script.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,17 +7,24 @@
|
|||||||
export default
|
export default
|
||||||
[ '$rootScope','Wait', 'generateList', 'inventoryScriptsListObject',
|
[ '$rootScope','Wait', 'generateList', 'inventoryScriptsListObject',
|
||||||
'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' , 'ProcessErrors',
|
'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' , 'ProcessErrors',
|
||||||
'Prompt', '$state', '$filter',
|
'Prompt', '$state', '$filter', 'rbacUiControlService',
|
||||||
function(
|
function(
|
||||||
$rootScope,Wait, GenerateList, inventoryScriptsListObject,
|
$rootScope,Wait, GenerateList, inventoryScriptsListObject,
|
||||||
GetBasePath, SearchInit, PaginateInit,
|
GetBasePath, SearchInit, PaginateInit,
|
||||||
Rest, ProcessErrors, Prompt, $state, $filter
|
Rest, ProcessErrors, Prompt, $state, $filter, rbacUiControlService
|
||||||
) {
|
) {
|
||||||
var scope = $rootScope.$new(),
|
var scope = $rootScope.$new(),
|
||||||
defaultUrl = GetBasePath('inventory_scripts'),
|
defaultUrl = GetBasePath('inventory_scripts'),
|
||||||
list = inventoryScriptsListObject,
|
list = inventoryScriptsListObject,
|
||||||
view = GenerateList;
|
view = GenerateList;
|
||||||
|
|
||||||
|
scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd("inventory_scripts")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
view.inject( list, {
|
view.inject( list, {
|
||||||
mode: 'edit',
|
mode: 'edit',
|
||||||
scope: scope
|
scope: scope
|
||||||
|
|||||||
@@ -21,6 +21,15 @@
|
|||||||
$state, CreateSelect2, $q
|
$state, CreateSelect2, $q
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
Rest.setUrl(GetBasePath('job_templates'));
|
||||||
|
Rest.options()
|
||||||
|
.success(function(data) {
|
||||||
|
if (!data.actions.POST) {
|
||||||
|
$state.go("^");
|
||||||
|
Alert('Permission Error', 'You do not have permission to add a job template.', 'alert-info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
var defaultUrl = GetBasePath('job_templates'),
|
var defaultUrl = GetBasePath('job_templates'),
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ export default
|
|||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var defaultUrl = GetBasePath('job_templates'),
|
var defaultUrl = GetBasePath('job_templates'),
|
||||||
generator = GenerateForm,
|
generator = GenerateForm,
|
||||||
form = JobTemplateForm(),
|
form = JobTemplateForm(),
|
||||||
|
|||||||
@@ -10,18 +10,24 @@ export default
|
|||||||
'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList',
|
'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList',
|
||||||
'LookUpInit', 'InitiatePlaybookRun', 'Wait', '$compile',
|
'LookUpInit', 'InitiatePlaybookRun', 'Wait', '$compile',
|
||||||
'$state', '$filter',
|
'$state', '$filter', 'rbacUiControlService',
|
||||||
|
|
||||||
function(
|
function(
|
||||||
$scope, $rootScope, $location, $log,
|
$scope, $rootScope, $location, $log,
|
||||||
$stateParams, Rest, Alert, JobTemplateList, GenerateList, Prompt,
|
$stateParams, Rest, Alert, JobTemplateList, GenerateList, Prompt,
|
||||||
SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors,
|
SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors,
|
||||||
GetBasePath, JobTemplateForm, CredentialList, LookUpInit, InitiatePlaybookRun,
|
GetBasePath, JobTemplateForm, CredentialList, LookUpInit, InitiatePlaybookRun,
|
||||||
Wait, $compile, $state, $filter
|
Wait, $compile, $state, $filter, rbacUiControlService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd("job_templates")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
var list = JobTemplateList,
|
var list = JobTemplateList,
|
||||||
defaultUrl = GetBasePath('job_templates'),
|
defaultUrl = GetBasePath('job_templates'),
|
||||||
view = GenerateList,
|
view = GenerateList,
|
||||||
|
|||||||
@@ -70,6 +70,12 @@
|
|||||||
flex: 0 0 637px;
|
flex: 0 0 637px;
|
||||||
max-width: 637px;
|
max-width: 637px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SurveyMaker-previewPanel--viewOnly {
|
||||||
|
flex: 0 0 1155px;
|
||||||
|
max-width: 1155px;
|
||||||
|
}
|
||||||
|
|
||||||
.SurveyMaker-separatorPanel {
|
.SurveyMaker-separatorPanel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 51px;
|
flex: 0 0 51px;
|
||||||
|
|||||||
@@ -94,28 +94,33 @@ export default
|
|||||||
fieldActions: {
|
fieldActions: {
|
||||||
|
|
||||||
columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
|
columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
|
||||||
|
"view": {
|
||||||
|
mode: "all",
|
||||||
|
ngClick: "viewJob(all_job.id)",
|
||||||
|
awToolTip: "View the job",
|
||||||
|
dataPlacement: "top"
|
||||||
|
},
|
||||||
submit: {
|
submit: {
|
||||||
icon: 'icon-rocket',
|
icon: 'icon-rocket',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'relaunchJob($event, all_job.id)',
|
ngClick: 'relaunchJob($event, all_job.id)',
|
||||||
awToolTip: 'Relaunch using the same parameters',
|
awToolTip: 'Relaunch using the same parameters',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngHide: "all_job.type == 'system_job' "
|
ngShow: "!(all_job.type == 'system_job') && all_job.summary_fields.user_capabilities.start"
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'deleteJob(all_job.id)',
|
ngClick: 'deleteJob(all_job.id)',
|
||||||
awToolTip: 'Cancel the job',
|
awToolTip: 'Cancel the job',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngShow: "all_job.status === 'running'|| all_job.status === 'waiting' || all_job.status === 'pending'"
|
ngShow: "(all_job.status === 'running'|| all_job.status === 'waiting' || all_job.status === 'pending') && all_job.summary_fields.user_capabilities.start"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'deleteJob(all_job.id)',
|
ngClick: 'deleteJob(all_job.id)',
|
||||||
awToolTip: 'Delete the job',
|
awToolTip: 'Delete the job',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngShow: "all_job.status !== 'running' && all_job.status !== 'waiting' && all_job.status !== 'pending'"
|
ngShow: "(all_job.status !== 'running' && all_job.status !== 'waiting' && all_job.status !== 'pending') && all_job.summary_fields.user_capabilities.delete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,13 +100,14 @@ export default
|
|||||||
ngClick: 'relaunchJob($event, completed_job.id)',
|
ngClick: 'relaunchJob($event, completed_job.id)',
|
||||||
awToolTip: 'Relaunch using the same parameters',
|
awToolTip: 'Relaunch using the same parameters',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngHide: "completed_job.type == 'system_job' "
|
ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'deleteJob(completed_job.id)',
|
ngClick: 'deleteJob(completed_job.id)',
|
||||||
awToolTip: 'Delete the job',
|
awToolTip: 'Delete the job',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'completed_job.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,7 +72,17 @@ export default
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Edit credential',
|
awToolTip: 'Edit credential',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'credential.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
|
||||||
|
view: {
|
||||||
|
ngClick: "editCredential(credential.id)",
|
||||||
|
label: 'View',
|
||||||
|
"class": 'btn-sm',
|
||||||
|
awToolTip: 'View credential',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!credential.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": {
|
"delete": {
|
||||||
@@ -81,7 +91,8 @@ export default
|
|||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Delete credential',
|
awToolTip: 'Delete credential',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'credential.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ export default
|
|||||||
ngClick: 'addInventory()',
|
ngClick: 'addInventory()',
|
||||||
awToolTip: 'Create a new inventory',
|
awToolTip: 'Create a new inventory',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -103,13 +104,22 @@ export default
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
ngClick: 'editInventory(inventory.id)',
|
ngClick: 'editInventory(inventory.id)',
|
||||||
awToolTip: 'Edit inventory',
|
awToolTip: 'Edit inventory',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'inventory.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
label: 'View',
|
||||||
|
ngClick: 'editInventory(inventory.id)',
|
||||||
|
awToolTip: 'View inventory',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!inventory.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
ngClick: "deleteInventory(inventory.id, inventory.name)",
|
ngClick: "deleteInventory(inventory.id, inventory.name)",
|
||||||
awToolTip: 'Delete inventory',
|
awToolTip: 'Delete inventory',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'inventory.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ export default
|
|||||||
actionClass: 'btn List-buttonDefault',
|
actionClass: 'btn List-buttonDefault',
|
||||||
buttonContent: 'RUN COMMANDS',
|
buttonContent: 'RUN COMMANDS',
|
||||||
showTipWhenDisabled: true,
|
showTipWhenDisabled: true,
|
||||||
tooltipInnerClass: "Tooltip-wide"
|
tooltipInnerClass: "Tooltip-wide",
|
||||||
|
ngShow: 'canAdhoc'
|
||||||
// TODO: set up a tip watcher and change text based on when
|
// TODO: set up a tip watcher and change text based on when
|
||||||
// things are selected/not selected. This is started and
|
// things are selected/not selected. This is started and
|
||||||
// commented out in the inventory controller within the watchers.
|
// commented out in the inventory controller within the watchers.
|
||||||
@@ -155,7 +156,8 @@ export default
|
|||||||
ngClick: "createGroup()",
|
ngClick: "createGroup()",
|
||||||
awToolTip: "Create a new group",
|
awToolTip: "Create a new group",
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD GROUP'
|
buttonContent: '+ ADD GROUP',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -169,8 +171,8 @@ export default
|
|||||||
ngClick: 'updateGroup(group)',
|
ngClick: 'updateGroup(group)',
|
||||||
awToolTip: "{{ group.launch_tooltip }}",
|
awToolTip: "{{ group.launch_tooltip }}",
|
||||||
dataTipWatch: "group.launch_tooltip",
|
dataTipWatch: "group.launch_tooltip",
|
||||||
ngShow: "group.status !== 'running' && group.status " +
|
ngShow: "(group.status !== 'running' && group.status " +
|
||||||
"!== 'pending' && group.status !== 'updating'",
|
"!== 'pending' && group.status !== 'updating') && group.summary_fields.user_capabilities.start",
|
||||||
ngClass: "group.launch_class",
|
ngClass: "group.launch_class",
|
||||||
dataPlacement: "top",
|
dataPlacement: "top",
|
||||||
},
|
},
|
||||||
@@ -180,8 +182,8 @@ export default
|
|||||||
ngClick: "cancelUpdate(group.id)",
|
ngClick: "cancelUpdate(group.id)",
|
||||||
awToolTip: "Cancel sync process",
|
awToolTip: "Cancel sync process",
|
||||||
'class': 'red-txt',
|
'class': 'red-txt',
|
||||||
ngShow: "group.status == 'running' || group.status == 'pending' " +
|
ngShow: "(group.status == 'running' || group.status == 'pending' " +
|
||||||
"|| group.status == 'updating'",
|
"|| group.status == 'updating') && group.summary_fields.user_capabilities.start",
|
||||||
dataPlacement: "top",
|
dataPlacement: "top",
|
||||||
iconClass: "fa fa-minus-circle"
|
iconClass: "fa fa-minus-circle"
|
||||||
},
|
},
|
||||||
@@ -189,7 +191,7 @@ export default
|
|||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "copyMoveGroup(group.id)",
|
ngClick: "copyMoveGroup(group.id)",
|
||||||
awToolTip: 'Copy or move group',
|
awToolTip: 'Copy or move group',
|
||||||
ngShow: "group.id > 0",
|
ngShow: "group.id > 0 && group.summary_fields.user_capabilities.copy",
|
||||||
dataPlacement: "top"
|
dataPlacement: "top"
|
||||||
},
|
},
|
||||||
schedule: {
|
schedule: {
|
||||||
@@ -198,21 +200,31 @@ export default
|
|||||||
awToolTip: "{{ group.group_schedule_tooltip }}",
|
awToolTip: "{{ group.group_schedule_tooltip }}",
|
||||||
ngClass: "group.scm_type_class",
|
ngClass: "group.scm_type_class",
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngHide: "group.summary_fields.inventory_source.source === ''"
|
ngShow: "!(group.summary_fields.inventory_source.source === '') && group.summary_fields.user_capabilities.schedule"
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
//label: 'Edit',
|
//label: 'Edit',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "editGroup(group.id)",
|
ngClick: "editGroup(group.id)",
|
||||||
awToolTip: 'Edit group',
|
awToolTip: 'Edit group',
|
||||||
dataPlacement: "top"
|
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": {
|
"delete": {
|
||||||
//label: 'Delete',
|
//label: 'Delete',
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "deleteGroup(group)",
|
ngClick: "deleteGroup(group)",
|
||||||
awToolTip: 'Delete group',
|
awToolTip: 'Delete group',
|
||||||
dataPlacement: "top"
|
dataPlacement: "top",
|
||||||
|
ngShow: "group.summary_fields.user_capabilities.delete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -78,21 +78,31 @@ export default
|
|||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "copyMoveHost(host.id)",
|
ngClick: "copyMoveHost(host.id)",
|
||||||
awToolTip: 'Copy or move host to another group',
|
awToolTip: 'Copy or move host to another group',
|
||||||
dataPlacement: "top"
|
dataPlacement: "top",
|
||||||
|
ngShow: 'host.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
//label: 'Edit',
|
//label: 'Edit',
|
||||||
ngClick: "editHost(host.id)",
|
ngClick: "editHost(host.id)",
|
||||||
icon: 'icon-edit',
|
icon: 'icon-edit',
|
||||||
awToolTip: 'Edit host',
|
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": {
|
"delete": {
|
||||||
//label: 'Delete',
|
//label: 'Delete',
|
||||||
ngClick: "deleteHost(host.id, host.name)",
|
ngClick: "deleteHost(host.id, host.name)",
|
||||||
icon: 'icon-trash',
|
icon: 'icon-trash',
|
||||||
awToolTip: 'Delete host',
|
awToolTip: 'Delete host',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'host.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -122,7 +132,8 @@ export default
|
|||||||
ngClick: "createHost()",
|
ngClick: "createHost()",
|
||||||
awToolTip: "Create a new host",
|
awToolTip: "Create a new host",
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD HOST'
|
buttonContent: '+ ADD HOST',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ export default
|
|||||||
basePaths: ['job_templates'],
|
basePaths: ['job_templates'],
|
||||||
awToolTip: 'Create a new template',
|
awToolTip: 'Create a new template',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -68,7 +69,8 @@ export default
|
|||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'submitJob(job_template.id)',
|
ngClick: 'submitJob(job_template.id)',
|
||||||
awToolTip: 'Start a job using this template',
|
awToolTip: 'Start a job using this template',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'job_template.summary_fields.user_capabilities.start'
|
||||||
},
|
},
|
||||||
schedule: {
|
schedule: {
|
||||||
label: 'Schedule',
|
label: 'Schedule',
|
||||||
@@ -76,6 +78,7 @@ export default
|
|||||||
ngClick: 'scheduleJob(job_template.id)',
|
ngClick: 'scheduleJob(job_template.id)',
|
||||||
awToolTip: 'Schedule future job template runs',
|
awToolTip: 'Schedule future job template runs',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'job_template.summary_fields.user_capabilities.schedule'
|
||||||
},
|
},
|
||||||
copy: {
|
copy: {
|
||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
@@ -83,7 +86,7 @@ export default
|
|||||||
"class": 'btn-danger btn-xs',
|
"class": 'btn-danger btn-xs',
|
||||||
awToolTip: 'Copy template',
|
awToolTip: 'Copy template',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
ngHide: 'job_template.summary_fields.can_copy===false'
|
ngShow: 'job_template.summary_fields.user_capabilities.copy'
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
@@ -91,6 +94,15 @@ export default
|
|||||||
awToolTip: 'Edit template',
|
awToolTip: 'Edit template',
|
||||||
"class": 'btn-default btn-xs',
|
"class": 'btn-default btn-xs',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'job_template.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
label: 'View',
|
||||||
|
ngClick: "editJobTemplate(job_template.id)",
|
||||||
|
awToolTip: 'View template',
|
||||||
|
"class": 'btn-default btn-xs',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!job_template.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
@@ -98,6 +110,7 @@ export default
|
|||||||
"class": 'btn-danger btn-xs',
|
"class": 'btn-danger btn-xs',
|
||||||
awToolTip: 'Delete template',
|
awToolTip: 'Delete template',
|
||||||
dataPlacement: 'top',
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'job_template.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ export default
|
|||||||
ngClick: 'addProject()',
|
ngClick: 'addProject()',
|
||||||
awToolTip: 'Create a new project',
|
awToolTip: 'Create a new project',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: "canAdd"
|
||||||
},
|
},
|
||||||
refresh: {
|
refresh: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
@@ -86,30 +87,40 @@ export default
|
|||||||
awToolTip: "{{ project.scm_update_tooltip }}",
|
awToolTip: "{{ project.scm_update_tooltip }}",
|
||||||
dataTipWatch: "project.scm_update_tooltip",
|
dataTipWatch: "project.scm_update_tooltip",
|
||||||
ngClass: "project.scm_type_class",
|
ngClass: "project.scm_type_class",
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: "project.summary_fields.user_capabilities.start"
|
||||||
},
|
},
|
||||||
schedule: {
|
schedule: {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: "editSchedules(project.id)",
|
ngClick: "editSchedules(project.id)",
|
||||||
awToolTip: "{{ project.scm_schedule_tooltip }}",
|
awToolTip: "{{ project.scm_schedule_tooltip }}",
|
||||||
ngClass: "project.scm_type_class",
|
ngClass: "project.scm_type_class",
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: "project.summary_fields.user_capabilities.schedule"
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
ngClick: "editProject(project.id)",
|
ngClick: "editProject(project.id)",
|
||||||
awToolTip: 'Edit the project',
|
awToolTip: 'Edit the project',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: "project.summary_fields.user_capabilities.edit"
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
ngClick: "editProject(project.id)",
|
||||||
|
awToolTip: 'View the project',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: "!project.summary_fields.user_capabilities.edit",
|
||||||
|
icon: 'fa-eye',
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
ngClick: "deleteProject(project.id, project.name)",
|
ngClick: "deleteProject(project.id, project.name)",
|
||||||
awToolTip: 'Delete the project',
|
awToolTip: 'Delete the project',
|
||||||
ngShow: "project.status !== 'updating' && project.status !== 'running' && project.status !== 'pending'",
|
ngShow: "(project.status !== 'updating' && project.status !== 'running' && project.status !== 'pending') && project.summary_fields.user_capabilities.delete",
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top'
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: "cancelUpdate(project.id, project.name)",
|
ngClick: "cancelUpdate(project.id, project.name)",
|
||||||
awToolTip: 'Cancel the SCM update',
|
awToolTip: 'Cancel the SCM update',
|
||||||
ngShow: "project.status == 'updating' || project.status == 'running' || project.status == 'pending'",
|
ngShow: "(project.status == 'updating' || project.status == 'running' || project.status == 'pending') && project.summary_fields.user_capabilities.start",
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,13 +78,22 @@ export default
|
|||||||
mode: "all",
|
mode: "all",
|
||||||
ngClick: "editSchedule(schedule)",
|
ngClick: "editSchedule(schedule)",
|
||||||
awToolTip: "Edit the schedule",
|
awToolTip: "Edit the schedule",
|
||||||
dataPlacement: "top"
|
dataPlacement: "top",
|
||||||
|
ngShow: 'schedule.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
"view": {
|
||||||
|
mode: "all",
|
||||||
|
ngClick: "editSchedule(schedule)",
|
||||||
|
awToolTip: "View the schedule",
|
||||||
|
dataPlacement: "top",
|
||||||
|
ngShow: '!schedule.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
mode: 'all',
|
mode: 'all',
|
||||||
ngClick: 'deleteSchedule(schedule.id)',
|
ngClick: 'deleteSchedule(schedule.id)',
|
||||||
awToolTip: 'Delete the schedule',
|
awToolTip: 'Delete the schedule',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'schedule.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ export default
|
|||||||
ngClick: 'addSchedule()',
|
ngClick: 'addSchedule()',
|
||||||
awToolTip: 'Add a new schedule',
|
awToolTip: 'Add a new schedule',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -79,14 +80,23 @@ export default
|
|||||||
ngClick: "editSchedule(schedule.id)",
|
ngClick: "editSchedule(schedule.id)",
|
||||||
icon: 'icon-edit',
|
icon: 'icon-edit',
|
||||||
awToolTip: 'Edit schedule',
|
awToolTip: 'Edit schedule',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'schedule.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
label: 'View',
|
||||||
|
ngClick: "editSchedule(schedule.id)",
|
||||||
|
awToolTip: 'View schedule',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!schedule.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
ngClick: "deleteSchedule(schedule.id)",
|
ngClick: "deleteSchedule(schedule.id)",
|
||||||
icon: 'icon-trash',
|
icon: 'icon-trash',
|
||||||
awToolTip: 'Delete schedule',
|
awToolTip: 'Delete schedule',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'schedule.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ export default
|
|||||||
ngClick: 'addTeam()',
|
ngClick: 'addTeam()',
|
||||||
awToolTip: 'Create a new team',
|
awToolTip: 'Create a new team',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -61,16 +62,25 @@ export default
|
|||||||
icon: 'icon-edit',
|
icon: 'icon-edit',
|
||||||
"class": 'btn-xs btn-default',
|
"class": 'btn-xs btn-default',
|
||||||
awToolTip: 'Edit team',
|
awToolTip: 'Edit team',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'team.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
label: 'View',
|
||||||
|
ngClick: "editTeam(team.id)",
|
||||||
|
"class": 'btn-xs btn-default',
|
||||||
|
awToolTip: 'View team',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!team.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": {
|
"delete": {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
ngClick: "deleteTeam(team.id, team.name)",
|
ngClick: "deleteTeam(team.id, team.name)",
|
||||||
icon: 'icon-trash',
|
icon: 'icon-trash',
|
||||||
"class": 'btn-xs btn-danger',
|
"class": 'btn-xs btn-danger',
|
||||||
awToolTip: 'Delete team',
|
awToolTip: 'Delete team',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'team.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ export default
|
|||||||
basePaths: ['organizations', 'users'], // base path must be in list, or action not available
|
basePaths: ['organizations', 'users'], // base path must be in list, or action not available
|
||||||
awToolTip: 'Create a new user',
|
awToolTip: 'Create a new user',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -58,7 +59,17 @@ export default
|
|||||||
icon: 'icon-edit',
|
icon: 'icon-edit',
|
||||||
"class": 'btn-xs btn-default',
|
"class": 'btn-xs btn-default',
|
||||||
awToolTip: 'Edit user',
|
awToolTip: 'Edit user',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'user.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
|
||||||
|
view: {
|
||||||
|
label: 'View',
|
||||||
|
ngClick: "editUser(user.id)",
|
||||||
|
"class": 'btn-xs btn-default',
|
||||||
|
awToolTip: 'View user',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!user.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
|
|
||||||
"delete": {
|
"delete": {
|
||||||
@@ -67,7 +78,8 @@ export default
|
|||||||
icon: 'icon-trash',
|
icon: 'icon-trash',
|
||||||
"class": 'btn-xs btn-danger',
|
"class": 'btn-xs btn-danger',
|
||||||
awToolTip: 'Delete user',
|
awToolTip: 'Delete user',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'user.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<div class="MgmtCards-actionItems">
|
<div class="MgmtCards-actionItems">
|
||||||
<button class="MgmtCards-actionItem List-actionButton"
|
<button class="MgmtCards-actionItem List-actionButton"
|
||||||
ng-click='chooseRunJob(card.id, card.name)'
|
ng-click='chooseRunJob(card.id, card.name)'
|
||||||
|
ng-show='current_user.is_superuser'
|
||||||
data-placement="top" aw-tool-tip="Launch Management Job" data-original-title="" title="">
|
data-placement="top" aw-tool-tip="Launch Management Job" data-original-title="" title="">
|
||||||
<i class="MgmtCards-actionItemIcon icon-launch"></i>
|
<i class="MgmtCards-actionItemIcon icon-launch"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button class="MgmtCards-actionItem List-actionButton"
|
<button class="MgmtCards-actionItem List-actionButton"
|
||||||
ng-click='goToNotifications(card, card.id)'
|
ng-click='goToNotifications(card, card.id)'
|
||||||
|
ng-show='current_user.is_superuser'
|
||||||
data-placement="top" aw-tool-tip="Configure Notifications" data-original-title="" title="" ng-class="{'List-editButton--selected': activeCard === card.id && cardAction === 'notifications'}">
|
data-placement="top" aw-tool-tip="Configure Notifications" data-original-title="" title="" ng-class="{'List-editButton--selected': activeCard === card.id && cardAction === 'notifications'}">
|
||||||
<i class="MgmtCards-actionItemIcon fa fa-bell-o"></i>
|
<i class="MgmtCards-actionItemIcon fa fa-bell-o"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -9,14 +9,23 @@ export default
|
|||||||
'NotificationsFormObject', 'ProcessErrors', 'GetBasePath', 'Empty',
|
'NotificationsFormObject', 'ProcessErrors', 'GetBasePath', 'Empty',
|
||||||
'GenerateForm', 'SearchInit' , 'PaginateInit', 'LookUpInit',
|
'GenerateForm', 'SearchInit' , 'PaginateInit', 'LookUpInit',
|
||||||
'OrganizationList', '$scope', '$state', 'CreateSelect2', 'GetChoices',
|
'OrganizationList', '$scope', '$state', 'CreateSelect2', 'GetChoices',
|
||||||
'NotificationsTypeChange', 'ParseTypeChange',
|
'NotificationsTypeChange', 'ParseTypeChange', 'Alert',
|
||||||
function(
|
function(
|
||||||
$rootScope, pagination, $compile, SchedulerInit, Rest, Wait,
|
$rootScope, pagination, $compile, SchedulerInit, Rest, Wait,
|
||||||
NotificationsFormObject, ProcessErrors, GetBasePath, Empty,
|
NotificationsFormObject, ProcessErrors, GetBasePath, Empty,
|
||||||
GenerateForm, SearchInit, PaginateInit, LookUpInit,
|
GenerateForm, SearchInit, PaginateInit, LookUpInit,
|
||||||
OrganizationList, $scope, $state, CreateSelect2, GetChoices,
|
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,
|
var generator = GenerateForm,
|
||||||
form = NotificationsFormObject,
|
form = NotificationsFormObject,
|
||||||
url = GetBasePath('notification_templates');
|
url = GetBasePath('notification_templates');
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ export default
|
|||||||
url = GetBasePath('notification_templates');
|
url = GetBasePath('notification_templates');
|
||||||
|
|
||||||
$scope.notification_template = notification_template;
|
$scope.notification_template = notification_template;
|
||||||
|
|
||||||
|
$scope.$watch('notification_template.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
generator.inject(form, {
|
generator.inject(form, {
|
||||||
mode: 'edit' ,
|
mode: 'edit' ,
|
||||||
scope:$scope,
|
scope:$scope,
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ export default
|
|||||||
[ '$rootScope','Wait', 'generateList', 'NotificationTemplatesList',
|
[ '$rootScope','Wait', 'generateList', 'NotificationTemplatesList',
|
||||||
'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' ,
|
'GetBasePath' , 'SearchInit' , 'PaginateInit', 'Rest' ,
|
||||||
'ProcessErrors', 'Prompt', '$state', 'GetChoices', 'Empty', 'Find',
|
'ProcessErrors', 'Prompt', '$state', 'GetChoices', 'Empty', 'Find',
|
||||||
'ngToast', '$compile', '$filter',
|
'ngToast', '$compile', '$filter', 'rbacUiControlService',
|
||||||
function(
|
function(
|
||||||
$rootScope,Wait, GenerateList, NotificationTemplatesList,
|
$rootScope,Wait, GenerateList, NotificationTemplatesList,
|
||||||
GetBasePath, SearchInit, PaginateInit, Rest,
|
GetBasePath, SearchInit, PaginateInit, Rest,
|
||||||
ProcessErrors, Prompt, $state, GetChoices, Empty, Find, ngToast,
|
ProcessErrors, Prompt, $state, GetChoices, Empty, Find, ngToast,
|
||||||
$compile, $filter) {
|
$compile, $filter, rbacUiControlService) {
|
||||||
var scope = $rootScope.$new(),
|
var scope = $rootScope.$new(),
|
||||||
defaultUrl = GetBasePath('notification_templates'),
|
defaultUrl = GetBasePath('notification_templates'),
|
||||||
list = NotificationTemplatesList,
|
list = NotificationTemplatesList,
|
||||||
@@ -24,6 +24,13 @@ export default
|
|||||||
scope: scope
|
scope: scope
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd("notification_templates")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
scope.removePostRefresh = scope.$on('PostRefresh', function () {
|
scope.removePostRefresh = scope.$on('PostRefresh', function () {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
if (scope.notification_templates) {
|
if (scope.notification_templates) {
|
||||||
|
|||||||
@@ -27,13 +27,15 @@ export default function() {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: true,
|
addRequired: true,
|
||||||
editRequired: true,
|
editRequired: true,
|
||||||
capitalize: false
|
capitalize: false,
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
label: 'Description',
|
label: 'Description',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
addRequired: false,
|
addRequired: false,
|
||||||
editRequired: false
|
editRequired: false,
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
organization: {
|
organization: {
|
||||||
label: 'Organization',
|
label: 'Organization',
|
||||||
@@ -44,7 +46,8 @@ export default function() {
|
|||||||
awRequiredWhen: {
|
awRequiredWhen: {
|
||||||
reqExpression: "organizationrequired",
|
reqExpression: "organizationrequired",
|
||||||
init: "true"
|
init: "true"
|
||||||
}
|
},
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
notification_type: {
|
notification_type: {
|
||||||
label: 'Type',
|
label: 'Type',
|
||||||
@@ -54,13 +57,15 @@ export default function() {
|
|||||||
class: 'NotificationsForm-typeSelect',
|
class: 'NotificationsForm-typeSelect',
|
||||||
ngOptions: 'type.label for type in notification_type_options track by type.value',
|
ngOptions: 'type.label for type in notification_type_options track by type.value',
|
||||||
ngChange: 'typeChange()',
|
ngChange: 'typeChange()',
|
||||||
hasSubForm: true
|
hasSubForm: true,
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
username: {
|
username: {
|
||||||
label: 'Username',
|
label: 'Username',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
ngShow: "notification_type.value == 'email' ",
|
ngShow: "notification_type.value == 'email' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
|
|
||||||
host: {
|
host: {
|
||||||
@@ -71,7 +76,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'email' ",
|
ngShow: "notification_type.value == 'email' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
sender: {
|
sender: {
|
||||||
label: 'Sender Email',
|
label: 'Sender Email',
|
||||||
@@ -81,7 +87,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'email' ",
|
ngShow: "notification_type.value == 'email' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
recipients: {
|
recipients: {
|
||||||
label: 'Recipient List',
|
label: 'Recipient List',
|
||||||
@@ -97,7 +104,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'email' ",
|
ngShow: "notification_type.value == 'email' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
labelBind: 'passwordLabel',
|
labelBind: 'passwordLabel',
|
||||||
@@ -108,7 +116,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'email' || notification_type.value == 'irc' ",
|
ngShow: "notification_type.value == 'email' || notification_type.value == 'irc' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
port: {
|
port: {
|
||||||
labelBind: 'portLabel',
|
labelBind: 'portLabel',
|
||||||
@@ -122,7 +131,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'email' || notification_type.value == 'irc'",
|
ngShow: "notification_type.value == 'email' || notification_type.value == 'irc'",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
channels: {
|
channels: {
|
||||||
label: 'Destination Channels',
|
label: 'Destination Channels',
|
||||||
@@ -138,7 +148,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'slack'",
|
ngShow: "notification_type.value == 'slack'",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
rooms: {
|
rooms: {
|
||||||
label: 'Destination Channels',
|
label: 'Destination Channels',
|
||||||
@@ -154,7 +165,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'hipchat'",
|
ngShow: "notification_type.value == 'hipchat'",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
token: {
|
token: {
|
||||||
labelBind: 'tokenLabel',
|
labelBind: 'tokenLabel',
|
||||||
@@ -165,7 +177,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'slack' || notification_type.value == 'pagerduty' || notification_type.value == 'hipchat'",
|
ngShow: "notification_type.value == 'slack' || notification_type.value == 'pagerduty' || notification_type.value == 'hipchat'",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
account_token: {
|
account_token: {
|
||||||
label: 'Account Token',
|
label: 'Account Token',
|
||||||
@@ -176,7 +189,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'twilio' ",
|
ngShow: "notification_type.value == 'twilio' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
from_number: {
|
from_number: {
|
||||||
label: 'Source Phone Number',
|
label: 'Source Phone Number',
|
||||||
@@ -188,7 +202,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'twilio' ",
|
ngShow: "notification_type.value == 'twilio' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
to_numbers: {
|
to_numbers: {
|
||||||
label: 'Destination SMS Number',
|
label: 'Destination SMS Number',
|
||||||
@@ -204,7 +219,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'twilio' ",
|
ngShow: "notification_type.value == 'twilio' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
account_sid: {
|
account_sid: {
|
||||||
label: 'Account SID',
|
label: 'Account SID',
|
||||||
@@ -214,7 +230,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'twilio' ",
|
ngShow: "notification_type.value == 'twilio' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
subdomain: {
|
subdomain: {
|
||||||
label: 'Pagerduty subdomain',
|
label: 'Pagerduty subdomain',
|
||||||
@@ -224,7 +241,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'pagerduty' ",
|
ngShow: "notification_type.value == 'pagerduty' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
service_key: {
|
service_key: {
|
||||||
label: 'API Service/Integration Key',
|
label: 'API Service/Integration Key',
|
||||||
@@ -234,7 +252,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'pagerduty' ",
|
ngShow: "notification_type.value == 'pagerduty' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
client_name: {
|
client_name: {
|
||||||
label: 'Client Identifier',
|
label: 'Client Identifier',
|
||||||
@@ -244,7 +263,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'pagerduty' ",
|
ngShow: "notification_type.value == 'pagerduty' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
message_from: {
|
message_from: {
|
||||||
label: 'Label to be shown with notification',
|
label: 'Label to be shown with notification',
|
||||||
@@ -254,7 +274,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'hipchat' ",
|
ngShow: "notification_type.value == 'hipchat' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
api_url: {
|
api_url: {
|
||||||
label: 'API URL',
|
label: 'API URL',
|
||||||
@@ -265,7 +286,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'hipchat' ",
|
ngShow: "notification_type.value == 'hipchat' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
label: 'Notification Color',
|
label: 'Notification Color',
|
||||||
@@ -277,13 +299,15 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'hipchat' ",
|
ngShow: "notification_type.value == 'hipchat' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
notify: {
|
notify: {
|
||||||
label: 'Notify Channel',
|
label: 'Notify Channel',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
ngShow: "notification_type.value == 'hipchat' ",
|
ngShow: "notification_type.value == 'hipchat' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
label: 'Target URL',
|
label: 'Target URL',
|
||||||
@@ -293,7 +317,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'webhook' ",
|
ngShow: "notification_type.value == 'webhook' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
label: 'HTTP Headers',
|
label: 'HTTP Headers',
|
||||||
@@ -313,7 +338,8 @@ export default function() {
|
|||||||
'</pre></p>',
|
'</pre></p>',
|
||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
ngShow: "notification_type.value == 'webhook' ",
|
ngShow: "notification_type.value == 'webhook' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
label: 'IRC Server Address',
|
label: 'IRC Server Address',
|
||||||
@@ -323,7 +349,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'irc' ",
|
ngShow: "notification_type.value == 'irc' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
nickname: {
|
nickname: {
|
||||||
label: 'IRC Nick',
|
label: 'IRC Nick',
|
||||||
@@ -333,7 +360,8 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'irc' ",
|
ngShow: "notification_type.value == 'irc' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
targets: {
|
targets: {
|
||||||
label: 'Destination Channels or Users',
|
label: 'Destination Channels or Users',
|
||||||
@@ -349,13 +377,15 @@ export default function() {
|
|||||||
init: "false"
|
init: "false"
|
||||||
},
|
},
|
||||||
ngShow: "notification_type.value == 'irc' ",
|
ngShow: "notification_type.value == 'irc' ",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
use_ssl: {
|
use_ssl: {
|
||||||
label: 'SSL Connection',
|
label: 'SSL Connection',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
ngShow: "notification_type.value == 'irc'",
|
ngShow: "notification_type.value == 'irc'",
|
||||||
subForm: 'typeSubForm'
|
subForm: 'typeSubForm',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
checkbox_group: {
|
checkbox_group: {
|
||||||
label: 'Options',
|
label: 'Options',
|
||||||
@@ -367,13 +397,15 @@ export default function() {
|
|||||||
label: 'Use TLS',
|
label: 'Use TLS',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
ngShow: "notification_type.value == 'email' ",
|
ngShow: "notification_type.value == 'email' ",
|
||||||
labelClass: 'checkbox-options stack-inline'
|
labelClass: 'checkbox-options stack-inline',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}, {
|
}, {
|
||||||
name: 'use_ssl',
|
name: 'use_ssl',
|
||||||
label: 'Use SSL',
|
label: 'Use SSL',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
ngShow: "notification_type.value == 'email'",
|
ngShow: "notification_type.value == 'email'",
|
||||||
labelClass: 'checkbox-options stack-inline'
|
labelClass: 'checkbox-options stack-inline',
|
||||||
|
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -381,9 +413,15 @@ export default function() {
|
|||||||
buttons: { //for now always generates <button> tags
|
buttons: { //for now always generates <button> tags
|
||||||
cancel: {
|
cancel: {
|
||||||
ngClick: 'formCancel()',
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
ngClick: 'formCancel()',
|
||||||
|
ngShow: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
|
||||||
},
|
},
|
||||||
save: {
|
save: {
|
||||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
ngClick: 'formSave()',
|
||||||
|
ngShow: '(notification_template.summary_fields.user_capabilities.edit || canAdd)', //$scope.function to call on click, optional
|
||||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ export default function(){
|
|||||||
ngClick: 'addNotification()',
|
ngClick: 'addNotification()',
|
||||||
awToolTip: 'Create a new custom inventory',
|
awToolTip: 'Create a new custom inventory',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD'
|
buttonContent: '+ ADD',
|
||||||
|
ngShow: 'canAdd'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -62,7 +63,8 @@ export default function(){
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Test notification',
|
awToolTip: 'Test notification',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'notification_template.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
ngClick: "editNotification(notification_template.id)",
|
ngClick: "editNotification(notification_template.id)",
|
||||||
@@ -70,7 +72,16 @@ export default function(){
|
|||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Edit notification',
|
awToolTip: 'Edit notification',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'notification_template.summary_fields.user_capabilities.edit'
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
ngClick: "editNotification(notification_template.id)",
|
||||||
|
label: 'View',
|
||||||
|
"class": 'btn-sm',
|
||||||
|
awToolTip: 'View notification',
|
||||||
|
dataPlacement: 'top',
|
||||||
|
ngShow: '!notification_template.summary_fields.user_capabilities.edit'
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
ngClick: "deleteNotification(notification_template.id, notification_template.name)",
|
ngClick: "deleteNotification(notification_template.id, notification_template.name)",
|
||||||
@@ -78,7 +89,8 @@ export default function(){
|
|||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
"class": 'btn-sm',
|
"class": 'btn-sm',
|
||||||
awToolTip: 'Delete notification',
|
awToolTip: 'Delete notification',
|
||||||
dataPlacement: 'top'
|
dataPlacement: 'top',
|
||||||
|
ngShow: 'notification_template.summary_fields.user_capabilities.delete'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ export default function(){
|
|||||||
ngClick: 'addNotificationTemplate()',
|
ngClick: 'addNotificationTemplate()',
|
||||||
awToolTip: 'Create a new notification template',
|
awToolTip: 'Create a new notification template',
|
||||||
actionClass: 'btn List-buttonSubmit',
|
actionClass: 'btn List-buttonSubmit',
|
||||||
buttonContent: '+ ADD NOTIFICATION TEMPLATE'
|
buttonContent: '+ ADD NOTIFICATION TEMPLATE',
|
||||||
|
ngShow: 'current_user.is_superuser || (current_user_admin_orgs && current_user_admin_orgs.length > 0)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default ['Wait', 'GetBasePath', 'ProcessErrors', 'Rest', 'GetChoices',
|
export default ['Wait', 'GetBasePath', 'ProcessErrors', 'Rest', 'GetChoices',
|
||||||
'$state',
|
'$state', '$rootScope',
|
||||||
function(Wait, GetBasePath, ProcessErrors, Rest, GetChoices, $state) {
|
function(Wait, GetBasePath, ProcessErrors, Rest, GetChoices, $state, $rootScope) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
url = params.url,
|
url = params.url,
|
||||||
id = params.id;
|
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(){
|
scope.addNotificationTemplate = function(){
|
||||||
$state.go('notifications.add');
|
$state.go('notifications.add');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,15 @@ export default ['$scope', '$rootScope', '$compile', '$location',
|
|||||||
$stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors,
|
$stateParams, OrganizationForm, GenerateForm, Rest, Alert, ProcessErrors,
|
||||||
ClearScope, GetBasePath, ReturnToCaller, Wait, $state) {
|
ClearScope, GetBasePath, ReturnToCaller, Wait, $state) {
|
||||||
|
|
||||||
|
Rest.setUrl(GetBasePath('organizations'));
|
||||||
|
Rest.options()
|
||||||
|
.success(function(data) {
|
||||||
|
if (!data.actions.POST) {
|
||||||
|
$state.go("^");
|
||||||
|
Alert('Permission Error', 'You do not have permission to add an organization.', 'alert-info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
// Inject dynamic view
|
// Inject dynamic view
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ export default ['$scope', '$rootScope', '$compile', '$location',
|
|||||||
id = $stateParams.organization_id,
|
id = $stateParams.organization_id,
|
||||||
relatedSets = {};
|
relatedSets = {};
|
||||||
|
|
||||||
|
$scope.$watch('organization_obj.summary_fields.user_capabilities.edit', function(val) {
|
||||||
|
if (val === false) {
|
||||||
|
$scope.canAdd = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$scope.$parent.activeMode = 'edit';
|
$scope.$parent.activeMode = 'edit';
|
||||||
|
|
||||||
$scope.$parent.activeCard = parseInt(id);
|
$scope.$parent.activeCard = parseInt(id);
|
||||||
|
|||||||
@@ -8,15 +8,22 @@ export default ['$stateParams', '$scope', '$rootScope', '$location',
|
|||||||
'$log', '$compile', 'Rest', 'PaginateInit',
|
'$log', '$compile', 'Rest', 'PaginateInit',
|
||||||
'SearchInit', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope',
|
'SearchInit', 'OrganizationList', 'Alert', 'Prompt', 'ClearScope',
|
||||||
'ProcessErrors', 'GetBasePath', 'Wait',
|
'ProcessErrors', 'GetBasePath', 'Wait',
|
||||||
'$state', 'generateList', 'Refresh', '$filter',
|
'$state', 'generateList', 'Refresh', '$filter', 'rbacUiControlService',
|
||||||
function($stateParams, $scope, $rootScope, $location,
|
function($stateParams, $scope, $rootScope, $location,
|
||||||
$log, $compile, Rest, PaginateInit,
|
$log, $compile, Rest, PaginateInit,
|
||||||
SearchInit, OrganizationList, Alert, Prompt, ClearScope,
|
SearchInit, OrganizationList, Alert, Prompt, ClearScope,
|
||||||
ProcessErrors, GetBasePath, Wait,
|
ProcessErrors, GetBasePath, Wait,
|
||||||
$state, generateList, Refresh, $filter) {
|
$state, generateList, Refresh, $filter, rbacUiControlService) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd("organizations")
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
var defaultUrl = GetBasePath('organizations'),
|
var defaultUrl = GetBasePath('organizations'),
|
||||||
list = OrganizationList,
|
list = OrganizationList,
|
||||||
pageSize = 24,
|
pageSize = 24,
|
||||||
@@ -25,6 +32,7 @@ export default ['$stateParams', '$scope', '$rootScope', '$location',
|
|||||||
var parseCardData = function(cards) {
|
var parseCardData = function(cards) {
|
||||||
return cards.map(function(card) {
|
return cards.map(function(card) {
|
||||||
var val = {}, url = '/#/organizations/' + card.id + '/';
|
var val = {}, url = '/#/organizations/' + card.id + '/';
|
||||||
|
val.user_capabilities = card.summary_fields.user_capabilities;
|
||||||
val.name = card.name;
|
val.name = card.name;
|
||||||
val.id = card.id;
|
val.id = card.id;
|
||||||
val.description = card.description || undefined;
|
val.description = card.description || undefined;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<div class="List-actions">
|
<div class="List-actions">
|
||||||
<button class="btn List-buttonSubmit"
|
<button class="btn List-buttonSubmit"
|
||||||
aw-tool-tip="Create a new organization"
|
aw-tool-tip="Create a new organization"
|
||||||
|
ng-show="canAdd"
|
||||||
ng-click="addOrganization()">
|
ng-click="addOrganization()">
|
||||||
+ ADD
|
+ ADD
|
||||||
</button>
|
</button>
|
||||||
@@ -31,13 +32,23 @@
|
|||||||
<div class="OrgCards-actionItems">
|
<div class="OrgCards-actionItems">
|
||||||
<button class="OrgCards-actionItem
|
<button class="OrgCards-actionItem
|
||||||
List-actionButton"
|
List-actionButton"
|
||||||
|
ng-show="card.user_capabilities.edit"
|
||||||
ng-class="{'List-editButton--selected': (activeCard === card.id || card.isActiveCard) && activeMode === 'edit' }"
|
ng-class="{'List-editButton--selected': (activeCard === card.id || card.isActiveCard) && activeMode === 'edit' }"
|
||||||
ng-click="editOrganization(card.id)">
|
ng-click="editOrganization(card.id)">
|
||||||
<i class="OrgCards-actionItemIcon fa fa-pencil">
|
<i class="OrgCards-actionItemIcon fa fa-pencil">
|
||||||
</i>
|
</i>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="OrgCards-actionItem
|
||||||
|
List-actionButton"
|
||||||
|
ng-show="!card.user_capabilities.edit"
|
||||||
|
ng-class="{'List-editButton--selected': (activeCard === card.id || card.isActiveCard) && activeMode === 'edit' }"
|
||||||
|
ng-click="editOrganization(card.id)">
|
||||||
|
<i class="OrgCards-actionItemIcon fa fa-search-plus">
|
||||||
|
</i>
|
||||||
|
</button>
|
||||||
<button class="OrgCards-actionItem List-actionButton
|
<button class="OrgCards-actionItem List-actionButton
|
||||||
List-actionButton--delete"
|
List-actionButton--delete"
|
||||||
|
ng-show="card.user_capabilities.delete"
|
||||||
ng-click="deleteOrganization(card.id, card.name)">
|
ng-click="deleteOrganization(card.id, card.name)">
|
||||||
<i class="OrgCards-actionItemIcon
|
<i class="OrgCards-actionItemIcon
|
||||||
fa fa-trash-o">
|
fa fa-trash-o">
|
||||||
|
|||||||
@@ -32,13 +32,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="SurveyMaker-content">
|
<div class="SurveyMaker-content">
|
||||||
<div class="SurveyMaker-questionPanel">
|
<div class="SurveyMaker-questionPanel" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">
|
||||||
<div id="survey_maker_question_form"></div>
|
<div id="survey_maker_question_form"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="SurveyMaker-separatorPanel">
|
<div class="SurveyMaker-separatorPanel" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">
|
||||||
<div class="SurveyMaker-contentSeparator"></div>
|
<div class="SurveyMaker-contentSeparator"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="SurveyMaker-previewPanel">
|
<div class="SurveyMaker-previewPanel" ng-class="{'SurveyMaker-previewPanel--viewOnly': !(job_template_obj.summary_fields.user_capabilities.edit || canAdd)}">
|
||||||
<div style="display: flex; flex-direction: column; width: 100%;">
|
<div style="display: flex; flex-direction: column; width: 100%;">
|
||||||
<div class="SurveyMaker-panelHeader">PREVIEW</div>
|
<div class="SurveyMaker-panelHeader">PREVIEW</div>
|
||||||
<div class="SurveyMaker-panelBody">
|
<div class="SurveyMaker-panelBody">
|
||||||
@@ -56,13 +56,13 @@
|
|||||||
<i>{{question.question_description}}</i>
|
<i>{{question.question_description}}</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="SurveyMaker-previewInputRow">
|
<div class="SurveyMaker-previewInputRow">
|
||||||
<span dnd-handle class="SurveyMaker-reorderButton" data-placement="top" aw-tool-tip="Drag to reorder question" data-original-title="" title="">
|
<span dnd-handle class="SurveyMaker-reorderButton" data-placement="top" aw-tool-tip="Drag to reorder question" data-original-title="" title="" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">
|
||||||
<i class="fa fa-ellipsis-v"></i>
|
<i class="fa fa-ellipsis-v"></i>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<i class="fa fa-ellipsis-v"></i>
|
<i class="fa fa-ellipsis-v"></i>
|
||||||
</span>
|
</span>
|
||||||
<survey-question class="SurveyMaker-previewInput" preview="true" question="question" ng-required="question.required" ng-disabled=true></survey-question>
|
<survey-question class="SurveyMaker-previewInput" preview="true" question="question" ng-required="question.required" ng-disabled=true></survey-question>
|
||||||
<div class="SurveyMaker-previewActions">
|
<div class="SurveyMaker-previewActions" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">
|
||||||
<button class="List-actionButton" data-placement="top" ng-class="{'SurveyMaker-previewActions--selected' : editQuestionIndex == $index}" ng-click="editQuestion($index)" aw-tool-tip="Edit question" data-original-title="" title="">
|
<button class="List-actionButton" data-placement="top" ng-class="{'SurveyMaker-previewActions--selected' : editQuestionIndex == $index}" ng-click="editQuestion($index)" aw-tool-tip="Edit question" data-original-title="" title="">
|
||||||
<i class="fa fa-pencil"></i>
|
<i class="fa fa-pencil"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -80,9 +80,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="SurveyMaker-panelFooter">
|
<div class="SurveyMaker-panelFooter">
|
||||||
<div class="Form-buttons">
|
<div class="Form-buttons">
|
||||||
<button id="survey-delete-button" class="btn btn-sm SurveyMaker-deleteButton" ng-show="survey_exists" ng-click="showDeleteOverlay('survey')">DELETE SURVEY</button>
|
<button id="survey-delete-button" class="btn btn-sm SurveyMaker-deleteButton" ng-show="survey_exists && (job_template_obj.summary_fields.user_capabilities.edit || canAdd)" ng-click="showDeleteOverlay('survey')">DELETE SURVEY</button>
|
||||||
<button id="survey-close-button" class="btn btn-sm Form-buttonDefault" ng-click="closeSurvey('survey-modal-dialog')">CANCEL</button>
|
<button id="survey-close-button" class="btn btn-sm Form-buttonDefault" ng-click="closeSurvey('survey-modal-dialog')" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">CANCEL</button>
|
||||||
<button id="survey-save-button" class="btn btn-sm Form-saveButton" ng-click="saveSurvey()" ng-disabled="survey_questions.length < 1 || !can_edit || editQuestionIndex !== null">SAVE</button>
|
<button id="survey-close-button" class="btn btn-sm Form-buttonDefault" ng-click="closeSurvey('survey-modal-dialog')" ng-show="!(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">CLOSE</button>
|
||||||
|
<button id="survey-save-button" class="btn btn-sm Form-saveButton" ng-click="saveSurvey()" ng-disabled="survey_questions.length < 1 || !can_edit || editQuestionIndex !== null" ng-show="(job_template_obj.summary_fields.user_capabilities.edit || canAdd)">SAVE</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
export default [
|
export default [
|
||||||
'$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest',
|
'$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest',
|
||||||
'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Wait',
|
'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Wait',
|
||||||
'Find', 'LoadSchedulesScope', 'GetChoices', '$q', '$state',
|
'Find', 'LoadSchedulesScope', 'GetChoices', '$q', '$state', 'rbacUiControlService',
|
||||||
function ($scope, $compile, $location, $stateParams,
|
function ($scope, $compile, $location, $stateParams,
|
||||||
SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
|
SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
|
||||||
GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices,
|
GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices,
|
||||||
$q, $state) {
|
$q, $state, rbacUiControlService) {
|
||||||
var schedList = _.cloneDeep(SchedulesList);
|
var schedList = _.cloneDeep(SchedulesList);
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
@@ -48,6 +48,14 @@ export default [
|
|||||||
}
|
}
|
||||||
$scope.removeParentLoaded = $scope.$on('ParentLoaded', function() {
|
$scope.removeParentLoaded = $scope.$on('ParentLoaded', function() {
|
||||||
url += "schedules/";
|
url += "schedules/";
|
||||||
|
|
||||||
|
$scope.canAdd = false;
|
||||||
|
|
||||||
|
rbacUiControlService.canAdd(url)
|
||||||
|
.then(function(canAdd) {
|
||||||
|
$scope.canAdd = canAdd;
|
||||||
|
});
|
||||||
|
|
||||||
schedList.well = true;
|
schedList.well = true;
|
||||||
|
|
||||||
// include name of item in listTitle
|
// include name of item in listTitle
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export default ['$compile', '$filter', '$state', '$stateParams', 'AddSchedule',
|
|||||||
'Rest', 'ParamPass',
|
'Rest', 'ParamPass',
|
||||||
function($compile, $filter, $state, $stateParams, AddSchedule, Wait, $scope,
|
function($compile, $filter, $state, $stateParams, AddSchedule, Wait, $scope,
|
||||||
$rootScope, CreateSelect2, ParseTypeChange, GetBasePath, Rest, ParamPass) {
|
$rootScope, CreateSelect2, ParseTypeChange, GetBasePath, Rest, ParamPass) {
|
||||||
|
|
||||||
$scope.processSchedulerEndDt = function(){
|
$scope.processSchedulerEndDt = function(){
|
||||||
// set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight
|
// set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight
|
||||||
var dt = new Date($scope.schedulerUTCTime);
|
var dt = new Date($scope.schedulerUTCTime);
|
||||||
|
|||||||
@@ -865,6 +865,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += ">";
|
html += ">";
|
||||||
html += "<input type=\"checkbox\" ng-model=\"" + field.subCheckbox.variable + "\" ";
|
html += "<input type=\"checkbox\" ng-model=\"" + field.subCheckbox.variable + "\" ";
|
||||||
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
@@ -987,6 +988,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
if (field.subCheckbox.ngDisabled) {
|
if (field.subCheckbox.ngDisabled) {
|
||||||
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
||||||
}
|
}
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
html += "</label>";
|
html += "</label>";
|
||||||
@@ -1084,6 +1086,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
if (field.subCheckbox.ngDisabled) {
|
if (field.subCheckbox.ngDisabled) {
|
||||||
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
||||||
}
|
}
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
html += "</label>";
|
html += "</label>";
|
||||||
@@ -1151,6 +1154,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
if (field.subCheckbox.ngDisabled) {
|
if (field.subCheckbox.ngDisabled) {
|
||||||
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
html += "ng-disabled='" + field.subCheckbox.ngDisabled + "'";
|
||||||
}
|
}
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
html += "</label>";
|
html += "</label>";
|
||||||
@@ -1199,6 +1203,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += (field.min || field.min === 0) ? this.attr(field, 'min') : "";
|
html += (field.min || field.min === 0) ? this.attr(field, 'min') : "";
|
||||||
html += (field.max) ? this.attr(field, 'max') : "";
|
html += (field.max) ? this.attr(field, 'max') : "";
|
||||||
html += (field.ngChange) ? this.attr(field, 'ngChange') : "";
|
html += (field.ngChange) ? this.attr(field, 'ngChange') : "";
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += (field.slider) ? "id=\"" + fld + "-number\"" : (field.id) ? this.attr(field, 'id') : "";
|
html += (field.slider) ? "id=\"" + fld + "-number\"" : (field.id) ? this.attr(field, 'id') : "";
|
||||||
html += (options.mode === 'edit' && field.editRequired) ? "required " : "";
|
html += (options.mode === 'edit' && field.editRequired) ? "required " : "";
|
||||||
html += (options.mode === 'add' && field.addRequired) ? "required " : "";
|
html += (options.mode === 'add' && field.addRequired) ? "required " : "";
|
||||||
@@ -1219,6 +1224,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += "<input type=\"checkbox\" ng-model=\"" +
|
html += "<input type=\"checkbox\" ng-model=\"" +
|
||||||
field.subCheckbox.variable + "\" ";
|
field.subCheckbox.variable + "\" ";
|
||||||
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
@@ -1422,6 +1428,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += "<input type=\"checkbox\" ng-model=\"" +
|
html += "<input type=\"checkbox\" ng-model=\"" +
|
||||||
field.subCheckbox.variable + "\" ";
|
field.subCheckbox.variable + "\" ";
|
||||||
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
html += (field.subCheckbox.ngChange) ? "ng-change=\"" + field.subCheckbox.ngChange + "\" " : "";
|
||||||
|
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
|
||||||
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
html += "id=\"" + this.form.name + "_" + fld + "_ask_chbox\" ";
|
||||||
html += ">";
|
html += ">";
|
||||||
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
html += field.subCheckbox.text ? field.subCheckbox.text : "";
|
||||||
@@ -1693,6 +1700,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
button.label = 'Cancel';
|
button.label = 'Cancel';
|
||||||
button['class'] = 'Form-cancelButton';
|
button['class'] = 'Form-cancelButton';
|
||||||
}
|
}
|
||||||
|
if (btn === 'close') {
|
||||||
|
button.label = 'Close';
|
||||||
|
button['class'] = 'Form-cancelButton';
|
||||||
|
}
|
||||||
if (btn === 'launch') {
|
if (btn === 'launch') {
|
||||||
button.label = 'Launch';
|
button.label = 'Launch';
|
||||||
button['class'] = 'Form-launchButton';
|
button['class'] = 'Form-launchButton';
|
||||||
@@ -1705,6 +1716,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
button.label = 'Edit Survey';
|
button.label = 'Edit Survey';
|
||||||
button['class'] = 'Form-surveyButton';
|
button['class'] = 'Form-surveyButton';
|
||||||
}
|
}
|
||||||
|
if (btn === 'view_survey') {
|
||||||
|
button.label = 'View Survey';
|
||||||
|
button['class'] = 'Form-surveyButton';
|
||||||
|
}
|
||||||
|
|
||||||
// Build button HTML
|
// Build button HTML
|
||||||
html += "<button type=\"button\" ";
|
html += "<button type=\"button\" ";
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ import lodashAsPromised from './lodash-as-promised';
|
|||||||
import stringFilters from './string-filters/main';
|
import stringFilters from './string-filters/main';
|
||||||
import truncatedText from './truncated-text.directive';
|
import truncatedText from './truncated-text.directive';
|
||||||
import stateExtender from './stateExtender.provider';
|
import stateExtender from './stateExtender.provider';
|
||||||
|
import rbacUiControl from './rbacUiControl';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('shared', [listGenerator.name,
|
angular.module('shared', [listGenerator.name,
|
||||||
pagination.name,
|
pagination.name,
|
||||||
stringFilters.name,
|
stringFilters.name,
|
||||||
'ui.router'
|
'ui.router',
|
||||||
|
rbacUiControl.name
|
||||||
])
|
])
|
||||||
.factory('lodashAsPromised', lodashAsPromised)
|
.factory('lodashAsPromised', lodashAsPromised)
|
||||||
.directive('truncatedText', truncatedText)
|
.directive('truncatedText', truncatedText)
|
||||||
|
|||||||
32
awx/ui/client/src/shared/rbacUiControl.js
Normal file
32
awx/ui/client/src/shared/rbacUiControl.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2015 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('rbacUiControl', [])
|
||||||
|
.service('rbacUiControlService', ['$q', 'GetBasePath', 'Rest', 'Wait', function($q, GetBasePath, Rest, Wait){
|
||||||
|
this.canAdd = function(apiPath) {
|
||||||
|
var canAddVal = $q.defer();
|
||||||
|
|
||||||
|
if (apiPath.indexOf("api/v1") > -1) {
|
||||||
|
Rest.setUrl(apiPath);
|
||||||
|
} else {
|
||||||
|
Rest.setUrl(GetBasePath(apiPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wait("start");
|
||||||
|
Rest.options()
|
||||||
|
.success(function(data) {
|
||||||
|
if (data.actions.POST) {
|
||||||
|
canAddVal.resolve(true);
|
||||||
|
} else {
|
||||||
|
canAddVal.reject(false);
|
||||||
|
}
|
||||||
|
Wait("stop");
|
||||||
|
});
|
||||||
|
|
||||||
|
return canAddVal.promise;
|
||||||
|
};
|
||||||
|
}]);
|
||||||
@@ -9,13 +9,13 @@ module.exports = function(config) {
|
|||||||
browsers: ['Chrome', 'Firefox'],
|
browsers: ['Chrome', 'Firefox'],
|
||||||
coverageReporter: {
|
coverageReporter: {
|
||||||
reporters: [
|
reporters: [
|
||||||
{ type: 'html', subdir: 'html' }
|
{ type: 'html', subdir: 'html' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
frameworks: [
|
frameworks: [
|
||||||
'jasmine',
|
'jasmine',
|
||||||
],
|
],
|
||||||
reporters: ['progress', 'coverage'],
|
reporters: ['progress', 'coverage', 'junit'],
|
||||||
files: [
|
files: [
|
||||||
'./client/src/app.js',
|
'./client/src/app.js',
|
||||||
'./node_modules/angular-mocks/angular-mocks.js',
|
'./node_modules/angular-mocks/angular-mocks.js',
|
||||||
@@ -86,7 +86,9 @@ module.exports = function(config) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
junitReporter: {
|
junitReporter: {
|
||||||
outputFile: 'coverage/test-results.xml'
|
outputDir: 'coverage',
|
||||||
|
outputFile: 'ui-unit-test-results.xml',
|
||||||
|
useBrowserName: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
618
awx/ui/npm-shrinkwrap.json
generated
618
awx/ui/npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@
|
|||||||
"expose-loader": "^0.7.1",
|
"expose-loader": "^0.7.1",
|
||||||
"grunt": "^1.0.1",
|
"grunt": "^1.0.1",
|
||||||
"grunt-browser-sync": "^2.2.0",
|
"grunt-browser-sync": "^2.2.0",
|
||||||
|
"grunt-cli": "^1.2.0",
|
||||||
"grunt-concurrent": "^2.3.0",
|
"grunt-concurrent": "^2.3.0",
|
||||||
"grunt-contrib-clean": "^1.0.0",
|
"grunt-contrib-clean": "^1.0.0",
|
||||||
"grunt-contrib-concat": "^1.0.1",
|
"grunt-contrib-concat": "^1.0.1",
|
||||||
@@ -56,12 +57,15 @@
|
|||||||
"karma-firefox-launcher": "^1.0.0",
|
"karma-firefox-launcher": "^1.0.0",
|
||||||
"karma-html2js-preprocessor": "^1.0.0",
|
"karma-html2js-preprocessor": "^1.0.0",
|
||||||
"karma-jasmine": "^1.0.2",
|
"karma-jasmine": "^1.0.2",
|
||||||
|
"karma-junit-reporter": "^1.1.0",
|
||||||
|
"karma-phantomjs-launcher": "^1.0.2",
|
||||||
"karma-sauce-launcher": "^1.0.0",
|
"karma-sauce-launcher": "^1.0.0",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^1.8.0",
|
"karma-webpack": "^1.8.0",
|
||||||
"less-plugin-autoprefix": "^1.4.2",
|
"less-plugin-autoprefix": "^1.4.2",
|
||||||
"load-grunt-configs": "^1.0.0",
|
"load-grunt-configs": "^1.0.0",
|
||||||
"load-grunt-tasks": "^3.5.0",
|
"load-grunt-tasks": "^3.5.0",
|
||||||
|
"phantomjs-prebuilt": "^2.1.12",
|
||||||
"time-grunt": "^1.4.0",
|
"time-grunt": "^1.4.0",
|
||||||
"webpack": "^1.13.1",
|
"webpack": "^1.13.1",
|
||||||
"webpack-dev-server": "^1.14.1"
|
"webpack-dev-server": "^1.14.1"
|
||||||
|
|||||||
@@ -29,12 +29,34 @@ RUN yum install -y \
|
|||||||
# Remove the 2 lines below and uncomment the 3 lines above to build
|
# Remove the 2 lines below and uncomment the 3 lines above to build
|
||||||
# RPMs with the old JS build system.
|
# RPMs with the old JS build system.
|
||||||
RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
|
RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
|
||||||
RUN yum install -y nodejs
|
|
||||||
|
|
||||||
RUN npm set progress=false
|
RUN yum install -y nodejs
|
||||||
|
|
||||||
WORKDIR "/ansible-tower"
|
WORKDIR "/ansible-tower"
|
||||||
|
|
||||||
ENV VENV_BASE="/venv"
|
# Copy requirements files
|
||||||
|
COPY requirements/*.txt requirements/
|
||||||
|
|
||||||
|
# Copy __init__.py so the Makefile can retrieve `awx.__version__`
|
||||||
|
COPY awx/__init__.py awx/
|
||||||
|
|
||||||
|
# Copy Makefile
|
||||||
|
COPY Makefile .
|
||||||
|
|
||||||
|
# Install tower runtime virtualenvs
|
||||||
|
ENV SWIG_FEATURES="-cpperraswarn -includeall -I/usr/include/openssl"
|
||||||
|
RUN make requirements
|
||||||
|
|
||||||
|
# Install tower test requirements
|
||||||
|
ENV VENV_BASE=""
|
||||||
|
RUN make requirements_jenkins
|
||||||
|
|
||||||
|
# Build front-end deps
|
||||||
|
COPY awx/ui/package.json awx/ui/
|
||||||
|
|
||||||
|
RUN npm set progress=false
|
||||||
|
|
||||||
|
RUN make ui-deps-built
|
||||||
|
|
||||||
ENTRYPOINT ["/bin/bash", "-c"]
|
ENTRYPOINT ["/bin/bash", "-c"]
|
||||||
CMD ["bash"]
|
CMD ["bash"]
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ $ docker-compose -f tools/docker-compose/unit-tests/docker-compose.yml run unit-
|
|||||||
|
|
||||||
This will start the container, install the dependencies, and run the unit tests.
|
This will start the container, install the dependencies, and run the unit tests.
|
||||||
|
|
||||||
|
To rebuild:
|
||||||
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ docker-compose -f tools/docker-compose/unit-tests/docker-compose.yml build
|
||||||
|
```
|
||||||
|
|
||||||
If you just want to pop into a shell and poke around, run:
|
If you just want to pop into a shell and poke around, run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ services:
|
|||||||
dockerfile: tools/docker-compose/unit-tests/Dockerfile
|
dockerfile: tools/docker-compose/unit-tests/Dockerfile
|
||||||
environment:
|
environment:
|
||||||
SWIG_FEATURES: "-cpperraswarn -includeall -I/usr/include/openssl"
|
SWIG_FEATURES: "-cpperraswarn -includeall -I/usr/include/openssl"
|
||||||
command: ["make requirements_test test"]
|
TEST_DIRS: "awx/main/tests/unit"
|
||||||
|
command: ["make test"]
|
||||||
volumes:
|
volumes:
|
||||||
- ../../../:/ansible-tower
|
- ../../../:/ansible-tower
|
||||||
|
|||||||
Reference in New Issue
Block a user