mirror of
https://github.com/ansible/awx.git
synced 2026-02-25 15:06:02 -03:30
Merge branch 'release_3.0.0' into devel
* release_3.0.0: (22 commits) remove aws ask at runtime prompt from cred form config, resolves #3055 (#3058) fix missing URI encoding in event summary serch, kickback on #2980 (#3050) Switch base class for StateConflict Fixed password show/hide on enter for survey maker password type previews Fixed password show/hide on enter for survey taker survey questions where type is password Prevent populate_user from being registered multiple times. Fixing iterator used when jobs list refreshes Explicit super user check for JT can_delete Fix for populating teams for LDAP user. Update hubspot template for marketting Fix up flake8 Rolled back the onExit solution previously implemented to handle the backspace navigation on the job launch modal. New solution listens for state changes within the directive and cleans itself up. Switch disallowed object delete to 409 Password enter show/hide fix add test for CustomInventoryScript serializer Fixed bug where hitting enter in a password field in the job launch/survey maker modal would toggle the show/hide. Setting the local var CredentialList to the deep clone seems to be problematic. Moving this out so that the original object itself is overwritten which is how it's done in other places. (#3017) Jobs list page size (#3019) resolves kickback on #2980 (#3008) add read_role to organization select_related ...
This commit is contained in:
@@ -1283,7 +1283,9 @@ class CustomInventoryScriptSerializer(BaseSerializer):
|
||||
if obj is None:
|
||||
return ret
|
||||
request = self.context.get('request', None)
|
||||
if request.user not in obj.admin_role:
|
||||
if request.user not in obj.admin_role and \
|
||||
not request.user.is_superuser and \
|
||||
not request.user.is_system_auditor:
|
||||
ret['script'] = None
|
||||
return ret
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ class OrganizationList(OrganizationCountsMixin, ListCreateAPIView):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Organization.accessible_objects(self.request.user, 'read_role')
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'member_role')
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'member_role', 'read_role')
|
||||
return qs
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
@@ -2184,14 +2184,6 @@ class JobTemplateDetail(RetrieveUpdateDestroyAPIView):
|
||||
serializer_class = JobTemplateSerializer
|
||||
always_allow_superuser = False
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
can_delete = request.user.can_access(JobTemplate, 'delete', obj)
|
||||
if not can_delete:
|
||||
raise PermissionDenied("Cannot delete job template.")
|
||||
return super(JobTemplateDetail, self).destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
|
||||
|
||||
model = JobTemplate
|
||||
|
||||
@@ -25,7 +25,7 @@ from awx.main.conf import tower_settings
|
||||
|
||||
__all__ = ['get_user_queryset', 'check_user_access',
|
||||
'user_accessible_objects',
|
||||
'user_admin_role',]
|
||||
'user_admin_role', 'StateConflict',]
|
||||
|
||||
PERMISSION_TYPES = [
|
||||
PERM_INVENTORY_ADMIN,
|
||||
@@ -57,6 +57,8 @@ access_registry = {
|
||||
# ...
|
||||
}
|
||||
|
||||
class StateConflict(ValidationError):
|
||||
status_code = 409
|
||||
|
||||
def register_access(model_class, access_class):
|
||||
access_classes = access_registry.setdefault(model_class, [])
|
||||
@@ -315,11 +317,15 @@ class OrganizationAccess(BaseAccess):
|
||||
if not is_change_possible:
|
||||
return False
|
||||
active_jobs = []
|
||||
active_jobs.extend(Job.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES))
|
||||
active_jobs.extend(ProjectUpdate.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES))
|
||||
active_jobs.extend(InventoryUpdate.objects.filter(inventory_source__inventory__organization=obj, status__in=ACTIVE_STATES))
|
||||
active_jobs.extend([dict(type="job", id=o.id)
|
||||
for o in Job.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES)])
|
||||
active_jobs.extend([dict(type="project_update", id=o.id)
|
||||
for o in ProjectUpdate.objects.filter(project__in=obj.projects.all(), status__in=ACTIVE_STATES)])
|
||||
active_jobs.extend([dict(type="inventory_update", id=o.id)
|
||||
for o in InventoryUpdate.objects.filter(inventory_source__inventory__organization=obj, status__in=ACTIVE_STATES)])
|
||||
if len(active_jobs) > 0:
|
||||
raise ValidationError("Delete not allowed while there are jobs running. Number of jobs {}".format(len(active_jobs)))
|
||||
raise StateConflict({"conflict": "Resource is being used by running jobs",
|
||||
"active_jobs": active_jobs})
|
||||
return True
|
||||
|
||||
class InventoryAccess(BaseAccess):
|
||||
@@ -387,10 +393,13 @@ class InventoryAccess(BaseAccess):
|
||||
if not is_can_admin:
|
||||
return False
|
||||
active_jobs = []
|
||||
active_jobs.extend(Job.objects.filter(inventory=obj, status__in=ACTIVE_STATES))
|
||||
active_jobs.extend(InventoryUpdate.objects.filter(inventory_source__inventory=obj, status__in=ACTIVE_STATES))
|
||||
active_jobs.extend([dict(type="job", id=o.id)
|
||||
for o in Job.objects.filter(inventory=obj, status__in=ACTIVE_STATES)])
|
||||
active_jobs.extend([dict(type="inventory_update", id=o.id)
|
||||
for o in InventoryUpdate.objects.filter(inventory_source__inventory=obj, status__in=ACTIVE_STATES)])
|
||||
if len(active_jobs) > 0:
|
||||
raise ValidationError("Delete not allowed while there are jobs running. Number of jobs {}".format(len(active_jobs)))
|
||||
raise StateConflict({"conflict": "Resource is being used by running jobs",
|
||||
"active_jobs": active_jobs})
|
||||
return True
|
||||
|
||||
def can_run_ad_hoc_commands(self, obj):
|
||||
@@ -508,9 +517,11 @@ class GroupAccess(BaseAccess):
|
||||
if not is_delete_allowed:
|
||||
return False
|
||||
active_jobs = []
|
||||
active_jobs.extend(InventoryUpdate.objects.filter(inventory_source__in=obj.inventory_sources.all(), status__in=ACTIVE_STATES))
|
||||
active_jobs.extend([dict(type="inventory_update", id=o.id)
|
||||
for o in InventoryUpdate.objects.filter(inventory_source__in=obj.inventory_sources.all(), status__in=ACTIVE_STATES)])
|
||||
if len(active_jobs) > 0:
|
||||
raise ValidationError("Delete not allowed while there are jobs running. Number of jobs {}".format(len(active_jobs)))
|
||||
raise StateConflict({"conflict": "Resource is being used by running jobs",
|
||||
"active_jobs": active_jobs})
|
||||
return True
|
||||
|
||||
class InventorySourceAccess(BaseAccess):
|
||||
@@ -765,10 +776,13 @@ class ProjectAccess(BaseAccess):
|
||||
if not is_change_allowed:
|
||||
return False
|
||||
active_jobs = []
|
||||
active_jobs.extend(Job.objects.filter(project=obj, status__in=ACTIVE_STATES))
|
||||
active_jobs.extend(ProjectUpdate.objects.filter(project=obj, status__in=ACTIVE_STATES))
|
||||
active_jobs.extend([dict(type="job", id=o.id)
|
||||
for o in Job.objects.filter(project=obj, status__in=ACTIVE_STATES)])
|
||||
active_jobs.extend([dict(type="project_update", id=o.id)
|
||||
for o in ProjectUpdate.objects.filter(project=obj, status__in=ACTIVE_STATES)])
|
||||
if len(active_jobs) > 0:
|
||||
raise ValidationError("Delete not allowed while there are jobs running. Number of jobs {}".format(len(active_jobs)))
|
||||
raise StateConflict({"conflict": "Resource is being used by running jobs",
|
||||
"active_jobs": active_jobs})
|
||||
return True
|
||||
|
||||
@check_superuser
|
||||
@@ -989,14 +1003,15 @@ class JobTemplateAccess(BaseAccess):
|
||||
|
||||
return True
|
||||
|
||||
@check_superuser
|
||||
def can_delete(self, obj):
|
||||
is_delete_allowed = self.user in obj.admin_role
|
||||
is_delete_allowed = self.user.is_superuser or self.user in obj.admin_role
|
||||
if not is_delete_allowed:
|
||||
return False
|
||||
active_jobs = obj.jobs.filter(status__in=ACTIVE_STATES)
|
||||
active_jobs = [dict(type="job", id=o.id)
|
||||
for o in obj.jobs.filter(status__in=ACTIVE_STATES)]
|
||||
if len(active_jobs) > 0:
|
||||
raise ValidationError("Delete not allowed while there are jobs running. Number of jobs {}".format(len(active_jobs)))
|
||||
raise StateConflict({"conflict": "Resource is being used by running jobs",
|
||||
"active_jobs": active_jobs})
|
||||
return True
|
||||
|
||||
class JobAccess(BaseAccess):
|
||||
|
||||
@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='credential',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'use_role', b'admin_role', b'organization.auditor_role'], to='main.Role', null=b'True'),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'organization.auditor_role', b'use_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.RunPython(migration_utils.set_current_apps_for_migrations),
|
||||
migrations.RunPython(rbac.rebuild_role_hierarchy),
|
||||
|
||||
@@ -335,3 +335,15 @@ def test_jt_without_project(inventory):
|
||||
data["job_type"] = "scan"
|
||||
serializer = JobTemplateSerializer(data=data)
|
||||
assert serializer.is_valid()
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_disallow_template_delete_on_running_job(job_template_factory, delete, admin_user):
|
||||
objects = job_template_factory('jt',
|
||||
credential='c',
|
||||
job_type="run",
|
||||
project='p',
|
||||
inventory='i',
|
||||
organization='o')
|
||||
objects.job_template.create_unified_job()
|
||||
delete_response = delete(reverse('api:job_template_detail', args=[objects.job_template.pk]), user=admin_user)
|
||||
assert delete_response.status_code == 409
|
||||
|
||||
@@ -1,14 +1,31 @@
|
||||
# Python
|
||||
import pytest
|
||||
import mock
|
||||
from mock import PropertyMock
|
||||
import json
|
||||
|
||||
# AWX
|
||||
from awx.api.serializers import JobTemplateSerializer, JobSerializer, JobOptionsSerializer
|
||||
from awx.main.models import Label, Job
|
||||
from awx.api.serializers import (
|
||||
JobTemplateSerializer,
|
||||
JobSerializer,
|
||||
JobOptionsSerializer,
|
||||
CustomInventoryScriptSerializer,
|
||||
)
|
||||
from awx.main.models import (
|
||||
Label,
|
||||
Job,
|
||||
CustomInventoryScript,
|
||||
User,
|
||||
)
|
||||
|
||||
#DRF
|
||||
from rest_framework.request import Request
|
||||
from rest_framework import serializers
|
||||
from rest_framework.test import (
|
||||
APIRequestFactory,
|
||||
force_authenticate,
|
||||
)
|
||||
|
||||
|
||||
def mock_JT_resource_data():
|
||||
return ({}, [])
|
||||
@@ -189,3 +206,30 @@ class TestJobTemplateSerializerValidation(object):
|
||||
for ev in self.bad_extra_vars:
|
||||
with pytest.raises(serializers.ValidationError):
|
||||
serializer.validate_extra_vars(ev)
|
||||
|
||||
class TestCustomInventoryScriptSerializer(object):
|
||||
|
||||
@pytest.mark.parametrize("superuser,sysaudit,admin_role,value",
|
||||
((True, False, False, '#!/python'),
|
||||
(False, True, False, '#!/python'),
|
||||
(False, False, True, '#!/python'),
|
||||
(False, False, False, None)))
|
||||
def test_to_representation_orphan(self, superuser, sysaudit, admin_role, value):
|
||||
with mock.patch.object(CustomInventoryScriptSerializer, 'get_summary_fields', return_value={}):
|
||||
User.add_to_class('is_system_auditor', sysaudit)
|
||||
user = User(username="root", is_superuser=superuser)
|
||||
roles = [user] if admin_role else []
|
||||
|
||||
with mock.patch('awx.main.models.CustomInventoryScript.admin_role', new_callable=PropertyMock, return_value=roles):
|
||||
cis = CustomInventoryScript(pk=1, script='#!/python')
|
||||
serializer = CustomInventoryScriptSerializer()
|
||||
|
||||
factory = APIRequestFactory()
|
||||
wsgi_request = factory.post("/inventory_script/1", {'id':1}, format="json")
|
||||
force_authenticate(wsgi_request, user)
|
||||
|
||||
request = Request(wsgi_request)
|
||||
serializer.context['request'] = request
|
||||
|
||||
representation = serializer.to_representation(cis)
|
||||
assert representation['script'] == value
|
||||
|
||||
@@ -201,7 +201,7 @@ def _update_m2m_from_groups(user, ldap_user, rel, opts, remove=True):
|
||||
rel.remove(user)
|
||||
|
||||
|
||||
@receiver(populate_user)
|
||||
@receiver(populate_user, dispatch_uid='populate-ldap-user')
|
||||
def on_populate_user(sender, **kwargs):
|
||||
'''
|
||||
Handle signal from LDAP backend to populate the user object. Update user
|
||||
@@ -239,7 +239,7 @@ def on_populate_user(sender, **kwargs):
|
||||
team, created = Team.objects.get_or_create(name=team_name, organization=org)
|
||||
users_opts = team_opts.get('users', None)
|
||||
remove = bool(team_opts.get('remove', True))
|
||||
_update_m2m_from_groups(user, ldap_user, team.member_role.users, users_opts,
|
||||
_update_m2m_from_groups(user, ldap_user, team.member_role.members, users_opts,
|
||||
remove)
|
||||
|
||||
# Update user profile to store LDAP DN.
|
||||
|
||||
@@ -255,16 +255,6 @@ var tower = angular.module('Tower', [
|
||||
});
|
||||
});
|
||||
}]
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
}).
|
||||
|
||||
@@ -274,16 +264,6 @@ var tower = angular.module('Tower', [
|
||||
controller: JobsListController,
|
||||
ncyBreadcrumb: {
|
||||
label: "JOBS"
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
}).
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa
|
||||
scope: jobs_scope,
|
||||
list: AllJobsList,
|
||||
id: 'active-jobs',
|
||||
pageSize: 20,
|
||||
url: GetBasePath('unified_jobs') + '?status__in=pending,waiting,running,completed,failed,successful,error,canceled&order_by=-finished',
|
||||
searchParams: search_params,
|
||||
spinner: false
|
||||
@@ -77,15 +78,14 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa
|
||||
parent_scope: $scope,
|
||||
scope: scheduled_scope,
|
||||
list: ScheduledJobsList,
|
||||
pageSize: 20,
|
||||
id: 'scheduled-jobs-tab',
|
||||
searchSize: 'col-lg-4 col-md-4 col-sm-4 col-xs-12',
|
||||
url: GetBasePath('schedules') + '?next_run__isnull=false'
|
||||
});
|
||||
|
||||
$scope.refreshJobs = function() {
|
||||
jobs_scope.search('queued_job');
|
||||
jobs_scope.search('running_job');
|
||||
jobs_scope.search('completed_job');
|
||||
jobs_scope.search('all_job');
|
||||
scheduled_scope.search('schedule');
|
||||
};
|
||||
|
||||
|
||||
@@ -107,11 +107,6 @@ export default
|
||||
init: false
|
||||
},
|
||||
autocomplete: false,
|
||||
subCheckbox: {
|
||||
variable: 'secret_key_ask',
|
||||
text: 'Ask at runtime?',
|
||||
ngChange: 'ask(\'secret_key\', \'undefined\')'
|
||||
},
|
||||
clear: false,
|
||||
hasShowInputButton: true,
|
||||
apiField: 'password',
|
||||
|
||||
@@ -687,7 +687,7 @@ export default
|
||||
scope.plays = [];
|
||||
|
||||
url = scope.job.url + 'job_plays/?page_size=' + scope.playsMaxRows + '&order=id';
|
||||
url += (scope.search_play_name) ? '&play__icontains=' + scope.search_play_name : '';
|
||||
url += (scope.search_play_name) ? '&play__icontains=' + encodeURIComponent(scope.search_play_name) : '';
|
||||
url += (scope.search_play_status === 'failed') ? '&failed=true' : '';
|
||||
scope.playsLoading = true;
|
||||
Rest.setUrl(url);
|
||||
@@ -786,7 +786,7 @@ export default
|
||||
scope.tasks = [];
|
||||
if (scope.selectedPlay) {
|
||||
url = scope.job.url + 'job_tasks/?event_id=' + scope.selectedPlay;
|
||||
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
|
||||
url += (scope.search_task_name) ? '&task__icontains=' + encodeURIComponent(scope.search_task_name) : '';
|
||||
url += (scope.search_task_status === 'failed') ? '&failed=true' : '';
|
||||
url += '&page_size=' + scope.tasksMaxRows + '&order=id';
|
||||
scope.plays.every(function(p, idx) {
|
||||
|
||||
@@ -25,7 +25,6 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope,
|
||||
CredentialList = _.cloneDeep(CredentialList),
|
||||
defaultUrl = GetBasePath('job_templates'),
|
||||
// generator = GenerateForm,
|
||||
form = JobTemplateForm(),
|
||||
@@ -37,6 +36,8 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
||||
// checkSCMStatus, getPlaybooks, callback,
|
||||
// choicesCount = 0;
|
||||
|
||||
CredentialList = _.cloneDeep(CredentialList);
|
||||
|
||||
// The form uses awPopOverWatch directive to 'watch' scope.callback_help for changes. Each time the
|
||||
// popover is activated, a function checks the value of scope.callback_help before constructing the content.
|
||||
scope.setCallbackHelp = function() {
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
host_name: $scope.hostName,
|
||||
};
|
||||
if ($scope.searchStr && $scope.searchStr !== ''){
|
||||
params.or__play__icontains = $scope.searchStr;
|
||||
params.or__task__icontains = $scope.searchStr;
|
||||
params.or__play__icontains = encodeURIComponent($scope.searchStr);
|
||||
params.or__task__icontains = encodeURIComponent($scope.searchStr);
|
||||
}
|
||||
|
||||
switch($scope.activeFilter){
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
Wait('start');
|
||||
JobDetailService.getJobHostSummaries($stateParams.id, {
|
||||
page_size: page_size,
|
||||
host_name__icontains: $scope.searchTerm,
|
||||
host_name__icontains: encodeURIComponent($scope.searchTerm),
|
||||
}).success(function(res){
|
||||
$scope.hosts = res.results;
|
||||
$scope.next = res.next;
|
||||
|
||||
@@ -17,15 +17,5 @@ export default {
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
skip: true // Never display this state in breadcrumb.
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,15 +30,5 @@ export default {
|
||||
}]
|
||||
},
|
||||
templateUrl: templateUrl('job-detail/job-detail'),
|
||||
controller: 'JobDetailController',
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
controller: 'JobDetailController'
|
||||
};
|
||||
|
||||
@@ -89,6 +89,12 @@ export default [ 'templateUrl', 'CreateDialog', 'Wait', 'CreateSelect2', 'ParseT
|
||||
}
|
||||
};
|
||||
|
||||
scope.$on("$stateChangeStart", function() {
|
||||
scope.$evalAsync(function( scope ) {
|
||||
scope.clearDialog();
|
||||
});
|
||||
});
|
||||
|
||||
scope.init();
|
||||
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-password')" data-original-title="" title="">Show</button>
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-password')" data-original-title="" title="">Show</button>
|
||||
</span>
|
||||
<input id="job-submission-ssh-password" type="password" ng-model="passwords.ssh_password" ng-keydown="keydown($event)" name="ssh_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
<input id="job-submission-ssh-password" type="password" ng-model="passwords.ssh_password" name="ssh_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.ssh_password.$dirty && forms.credentialpasswords.ssh_password.$error.required">Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="ssh_password_api_error"></div>
|
||||
@@ -67,9 +67,9 @@
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-key-unlock_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-key-unlock')" data-original-title="" title="">Show</button>
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-ssh-key-unlock_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-ssh-key-unlock')" data-original-title="" title="">Show</button>
|
||||
</span>
|
||||
<input id="job-submission-ssh-key-unlock" type="password" ng-model="passwords.ssh_key_unlock" ng-keydown="keydown($event)" name="ssh_key_unlock" class="password-field form-control input-sm Form-textInput" required>
|
||||
<input id="job-submission-ssh-key-unlock" type="password" ng-model="passwords.ssh_key_unlock" name="ssh_key_unlock" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.ssh_key_unlock.$dirty && forms.credentialpasswords.ssh_key_unlock.$error.required">Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="ssh_key_unlock_api_error"></div>
|
||||
@@ -80,9 +80,9 @@
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-become-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-become-password')" data-original-title="" title="">Show</button>
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-become-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-become-password')" data-original-title="" title="">Show</button>
|
||||
</span>
|
||||
<input id="job-submission-become-password" type="password" ng-model="passwords.become_password" ng-keydown="keydown($event)" name="become_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
<input id="job-submission-become-password" type="password" ng-model="passwords.become_password" name="become_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.become_password.$dirty && forms.credentialpasswords.become_password.$error.required">Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="become_password_api_error"></div>
|
||||
@@ -93,9 +93,9 @@
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-vault-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-vault-password')" data-original-title="" title="">Show</button>
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="job-submission-vault-password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#job-submission-vault-password')" data-original-title="" title="">Show</button>
|
||||
</span>
|
||||
<input id="job-submission-vault-password" type="password" ng-model="passwords.vault_password" ng-keydown="keydown($event)" name="vault_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
<input id="job-submission-vault-password" type="password" ng-model="passwords.vault_password" name="vault_password" class="password-field form-control input-sm Form-textInput" required>
|
||||
</div>
|
||||
<div class="error" ng-show="forms.credentialpasswords.vault_password.$dirty && forms.credentialpasswords.vault_password.$error.required">Please enter a password.</div>
|
||||
<div class="error api-error" ng-bind="vault_password_api_error"></div>
|
||||
@@ -176,7 +176,7 @@
|
||||
<div ng-if="question.type === 'password'">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default show_input_button JobSubmission-passwordButton" id="survey_question_{{$index}}_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#survey_question_' + $index)" data-original-title="" title="">Show</button>
|
||||
<button type="button" class="btn btn-default show_input_button JobSubmission-passwordButton" id="survey_question_{{$index}}_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="togglePassword('#survey_question_' + $index)" data-original-title="" title="">Show</button>
|
||||
</span>
|
||||
<input id="survey_question_{{$index}}" type="password" ng-model="question.model" name="survey_question_{{$index}}" ng-required="question.required" ng-minlength="question.minlength" ng-maxlength="question.maxlength" class="form-control Form-textInput" autocomplete="false">
|
||||
</div>
|
||||
|
||||
@@ -16,14 +16,8 @@ export default {
|
||||
label: "CREATE JOB TEMPLATE"
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// close the survey maker modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
|
||||
if($("#survey-modal-dialog").hasClass('ui-dialog-content')) {
|
||||
$('#survey-modal-dialog').dialog('destroy');
|
||||
|
||||
@@ -19,14 +19,8 @@ export default {
|
||||
label: "{{name}}"
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// close the survey maker modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
|
||||
if($("#survey-modal-dialog").hasClass('ui-dialog-content')) {
|
||||
$('#survey-modal-dialog').dialog('destroy');
|
||||
|
||||
@@ -17,15 +17,5 @@ export default {
|
||||
},
|
||||
ncyBreadcrumb: {
|
||||
label: "JOB TEMPLATES"
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div ng-if="question.type === 'password'" class="input_area input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default SurveyMaker-previewPasswordButton" id="{{ question.variable + '_show_input_button' }}" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="toggleInput('#' + question.variable)" data-original-title="" title="">SHOW</button>
|
||||
<button type="button" class="btn btn-default SurveyMaker-previewPasswordButton" id="{{ question.variable + '_show_input_button' }}" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="toggleInput('#' + question.variable)" data-original-title="" title="">SHOW</button>
|
||||
</span>
|
||||
<input id="{{question.variable}}" type="password" name="" class="form-control ng-pristine ng-valid-api-error ng-invalid" autocomplete="false" ng-model="defaultValue" readonly>
|
||||
</div>
|
||||
|
||||
@@ -280,7 +280,7 @@ export default
|
||||
'<div>'+
|
||||
'<div class="input-group">'+
|
||||
'<span class="input-group-btn">'+
|
||||
'<button class="btn btn-default show_input_button" id="default_password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="toggleInput("#default_password")" data-original-title="" title="">SHOW</button>'+
|
||||
'<button type="button" class="btn btn-default show_input_button" id="default_password_show_input_button" aw-tool-tip="Toggle the display of plaintext." aw-tip-placement="top" ng-click="toggleInput("#default_password")" data-original-title="" title="">SHOW</button>'+
|
||||
'</span>'+
|
||||
'<input id="default_password" type="password" ng-model="default_password" name="default_password" class="form-control Form-textInput" autocomplete="false">'+
|
||||
'</div>'+
|
||||
|
||||
@@ -121,16 +121,6 @@ export default [
|
||||
features: ['FeaturesService', function(FeaturesService) {
|
||||
return FeaturesService.get();
|
||||
}]
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -24,15 +24,5 @@ export default {
|
||||
templateUrl: templateUrl('portal-mode/portal-mode-jobs'),
|
||||
controller: PortalModeJobsController
|
||||
}
|
||||
},
|
||||
onExit: function(){
|
||||
// close the job launch modal
|
||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||
// Destroy the dialog
|
||||
if($("#job-launch-modal").hasClass('ui-dialog-content')) {
|
||||
$('#job-launch-modal').dialog('destroy');
|
||||
}
|
||||
// Remove the directive from the page (if it's there)
|
||||
$('#content-container').find('submit-job').remove();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,7 +85,7 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', '$log', fu
|
||||
if (needsRequest.length) {
|
||||
// make the options request to reutrn the typeOptions
|
||||
var url = needsRequest[0].basePath ? GetBasePath(needsRequest[0].basePath) : basePath;
|
||||
if(url.indexOf('null') === 0 ){
|
||||
if(url.indexOf('null') === -1 ){
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.success(function (data) {
|
||||
|
||||
@@ -922,7 +922,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
||||
html += "'>\n";
|
||||
// TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field.
|
||||
html += "<span class='input-group-btn'>\n";
|
||||
html += "<button class='btn btn-default show_input_button Form-passwordButton' ";
|
||||
html += "<button type='button' class='btn btn-default show_input_button Form-passwordButton' ";
|
||||
html += buildId(field, fld + "_show_input_button", this.form);
|
||||
html += "aw-tool-tip='Toggle the display of plaintext.' aw-tip-placement='top' ";
|
||||
html += "tabindex='-1' ";
|
||||
|
||||
Reference in New Issue
Block a user