From 994a72967dab5ef8d6f35159985ea44f3b335a15 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Wed, 13 Jul 2016 17:23:00 -0400 Subject: [PATCH 01/12] Cascade delete teams when their organization is deleted --- .../migrations/0027_v300_team_migrations.py | 20 +++++++++++++ .../migrations/0028_v300_org_team_cascade.py | 20 +++++++++++++ awx/main/migrations/_team_cleanup.py | 30 +++++++++++++++++++ awx/main/models/organization.py | 2 +- 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 awx/main/migrations/0027_v300_team_migrations.py create mode 100644 awx/main/migrations/0028_v300_org_team_cascade.py create mode 100644 awx/main/migrations/_team_cleanup.py diff --git a/awx/main/migrations/0027_v300_team_migrations.py b/awx/main/migrations/0027_v300_team_migrations.py new file mode 100644 index 0000000000..b53fd8a969 --- /dev/null +++ b/awx/main/migrations/0027_v300_team_migrations.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from awx.main.migrations import _rbac as rbac +from awx.main.migrations import _team_cleanup as team_cleanup +from awx.main.migrations import _migration_utils as migration_utils +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0026_v300_credential_unique'), + ] + + operations = [ + migrations.RunPython(migration_utils.set_current_apps_for_migrations), + migrations.RunPython(team_cleanup.migrate_team), + migrations.RunPython(rbac.rebuild_role_hierarchy), + ] diff --git a/awx/main/migrations/0028_v300_org_team_cascade.py b/awx/main/migrations/0028_v300_org_team_cascade.py new file mode 100644 index 0000000000..bf798df3c3 --- /dev/null +++ b/awx/main/migrations/0028_v300_org_team_cascade.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import awx.main.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0027_v300_team_migrations'), + ] + + operations = [ + migrations.AlterField( + model_name='team', + name='organization', + field=models.ForeignKey(related_name='teams', to='main.Organization', null=True), + ), + ] diff --git a/awx/main/migrations/_team_cleanup.py b/awx/main/migrations/_team_cleanup.py new file mode 100644 index 0000000000..1a937d1f88 --- /dev/null +++ b/awx/main/migrations/_team_cleanup.py @@ -0,0 +1,30 @@ +# Python +import logging +from django.utils.encoding import smart_text + +logger = logging.getLogger(__name__) + +def log_migration(wrapped): + '''setup the logging mechanism for each migration method + as it runs, Django resets this, so we use a decorator + to re-add the handler for each method. + ''' + handler = logging.FileHandler("/tmp/tower_rbac_migrations.log", mode="a", encoding="UTF-8") + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setLevel(logging.DEBUG) + handler.setFormatter(formatter) + + def wrapper(*args, **kwargs): + logger.handlers = [] + logger.addHandler(handler) + return wrapped(*args, **kwargs) + return wrapper + +@log_migration +def migrate_team(apps, schema_editor): + '''If an orphan team exists that is still active, delete it.''' + Team = apps.get_model('main', 'Team') + for team in Team.objects.iterator(): + if team.organization is None: + logger.info(smart_text(u"Deleting orphaned team: {}".format(team.name))) + team.delete() diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 3717171411..79cb3facdc 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -93,7 +93,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin): 'Organization', blank=False, null=True, - on_delete=models.SET_NULL, + on_delete=models.CASCADE, related_name='teams', ) deprecated_projects = models.ManyToManyField( From e18d1425335e773911a6792749e058baf90fa06b Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Thu, 14 Jul 2016 14:29:34 -0400 Subject: [PATCH 02/12] Don't let normal users create orgless projects #3006 --- awx/api/serializers.py | 13 +++++++++++++ awx/main/tests/functional/test_projects.py | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 2f58b776f4..1487fe17e3 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -918,6 +918,19 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer): args=(obj.last_update.pk,)) return res + def validate(self, attrs): + organization = None + if 'organization' in attrs: + organization = attrs['organization'] + elif self.instance: + organization = self.instance.organization + + view = self.context.get('view', None) + if not organization and not view.request.user.is_superuser: + # Only allow super users to create orgless projects + raise serializers.ValidationError('Organization is missing') + return super(ProjectSerializer, self).validate(attrs) + class ProjectPlaybooksSerializer(ProjectSerializer): diff --git a/awx/main/tests/functional/test_projects.py b/awx/main/tests/functional/test_projects.py index 4c32d1dd69..7ac1675341 100644 --- a/awx/main/tests/functional/test_projects.py +++ b/awx/main/tests/functional/test_projects.py @@ -114,3 +114,11 @@ def test_create_project(post, organization, org_admin, org_member, admin, rando, assert result.status_code == expected_status_code if expected_status_code == 201: assert Project.objects.filter(name='Project', organization=organization).exists() + +@pytest.mark.django_db() +def test_create_project_null_organization(post, organization, admin): + post(reverse('api:project_list'), { 'name': 't', 'organization': None}, admin, expect=201) + +@pytest.mark.django_db() +def test_create_project_null_organization_xfail(post, organization, org_admin): + post(reverse('api:project_list'), { 'name': 't', 'organization': None}, org_admin, expect=400) From 68d5a702af292d2bf958422fed742b39b4757b0f Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 14:38:43 -0400 Subject: [PATCH 03/12] Team organization field made non-null --- awx/main/migrations/0028_v300_org_team_cascade.py | 3 ++- awx/main/models/organization.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/awx/main/migrations/0028_v300_org_team_cascade.py b/awx/main/migrations/0028_v300_org_team_cascade.py index bf798df3c3..80378c5729 100644 --- a/awx/main/migrations/0028_v300_org_team_cascade.py +++ b/awx/main/migrations/0028_v300_org_team_cascade.py @@ -15,6 +15,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='team', name='organization', - field=models.ForeignKey(related_name='teams', to='main.Organization', null=True), + field=models.ForeignKey(related_name='teams', to='main.Organization'), + preserve_default=False, ), ] diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 79cb3facdc..5f3dc9d7c9 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -92,7 +92,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin): organization = models.ForeignKey( 'Organization', blank=False, - null=True, + null=False, on_delete=models.CASCADE, related_name='teams', ) From 06c37d39ef7eb7b29919370f6c6a067d570e8fc2 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 14:43:25 -0400 Subject: [PATCH 04/12] Make development environment use ATOMIC_REQUESTS --- awx/settings/local_settings.py.docker_compose | 1 + 1 file changed, 1 insertion(+) diff --git a/awx/settings/local_settings.py.docker_compose b/awx/settings/local_settings.py.docker_compose index f7cf9f0c58..2e27a664ea 100644 --- a/awx/settings/local_settings.py.docker_compose +++ b/awx/settings/local_settings.py.docker_compose @@ -25,6 +25,7 @@ DATABASES = { 'NAME': 'awx-dev', 'USER': 'awx-dev', 'PASSWORD': 'AWXsome1', + 'ATOMIC_REQUESTS': True, 'HOST': 'postgres', 'PORT': '', } From 41d6d19bcb50d53a244cf0e39e5e00681cfb106e Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Thu, 14 Jul 2016 15:02:00 -0400 Subject: [PATCH 05/12] Added patch tests for updating project organizations --- awx/main/tests/functional/test_projects.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/awx/main/tests/functional/test_projects.py b/awx/main/tests/functional/test_projects.py index 7ac1675341..40ea659432 100644 --- a/awx/main/tests/functional/test_projects.py +++ b/awx/main/tests/functional/test_projects.py @@ -122,3 +122,11 @@ def test_create_project_null_organization(post, organization, admin): @pytest.mark.django_db() def test_create_project_null_organization_xfail(post, organization, org_admin): post(reverse('api:project_list'), { 'name': 't', 'organization': None}, org_admin, expect=400) + +@pytest.mark.django_db() +def test_patch_project_null_organization(patch, organization, project, admin): + patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': organization.id}, admin, expect=200) + +@pytest.mark.django_db() +def test_patch_project_null_organization_xfail(patch, project, org_admin): + patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': None}, org_admin, expect=400) From 8ed69d164117a56e3e0a9bd8148d61e22da930a7 Mon Sep 17 00:00:00 2001 From: Graham Mainwaring Date: Thu, 14 Jul 2016 15:34:16 -0400 Subject: [PATCH 06/12] Additional UI/JS licenses (#2974) * Additional UI/JS licenses --- docs/licenses/cowsay.txt | 26 ++++++++++++++++++++++++++ docs/licenses/font-awesome.txt | 13 +++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 docs/licenses/cowsay.txt create mode 100644 docs/licenses/font-awesome.txt diff --git a/docs/licenses/cowsay.txt b/docs/licenses/cowsay.txt new file mode 100644 index 0000000000..a58a648c73 --- /dev/null +++ b/docs/licenses/cowsay.txt @@ -0,0 +1,26 @@ +cowsay is licensed under the following MIT license: + +==== +Copyright (c) 2012 Fabio Crisci + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +==== + +The original idea of cowsay come from [Tony Monroe](http://www.nog.net/~tony/) - [cowsay](https://github.com/schacon/cowsay) diff --git a/docs/licenses/font-awesome.txt b/docs/licenses/font-awesome.txt new file mode 100644 index 0000000000..0928d89347 --- /dev/null +++ b/docs/licenses/font-awesome.txt @@ -0,0 +1,13 @@ +Font License + +Applies to all desktop and webfont files in the following directory: font-awesome/fonts/. +License: SIL OFL 1.1 +URL: http://scripts.sil.org/OFL + + + +Code License + +Applies to all CSS and LESS files in the following directories: font-awesome/css/, font-awesome/less/, and font-awesome/scss/. +License: MIT License +URL: http://opensource.org/licenses/mit-license.html From 4ffc062d1963982eab7cb0a1736bcacb2414141c Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Thu, 14 Jul 2016 15:35:46 -0400 Subject: [PATCH 07/12] resolves kickback on #2976 (#3009) --- awx/ui/client/src/controllers/Projects.js | 2 ++ awx/ui/client/src/helpers/JobTemplates.js | 1 + .../src/inventories/manage/groups/groups-add.controller.js | 1 + .../src/inventories/manage/groups/groups-edit.controller.js | 1 + .../src/job-templates/edit/job-templates-edit.controller.js | 3 ++- 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/controllers/Projects.js b/awx/ui/client/src/controllers/Projects.js index 4dbb111f79..1b641ab97a 100644 --- a/awx/ui/client/src/controllers/Projects.js +++ b/awx/ui/client/src/controllers/Projects.js @@ -392,6 +392,7 @@ export function ProjectsAdd(Refresh, $scope, $rootScope, $compile, $location, $l master = {}; // remove "type" field from search options + CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; generator.inject(form, { mode: 'add', related: false, scope: $scope }); @@ -571,6 +572,7 @@ export function ProjectsEdit($scope, $rootScope, $compile, $location, $log, relatedSets = {}; // remove "type" field from search options + CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; diff --git a/awx/ui/client/src/helpers/JobTemplates.js b/awx/ui/client/src/helpers/JobTemplates.js index 55b2419390..55a4a9aa5f 100644 --- a/awx/ui/client/src/helpers/JobTemplates.js +++ b/awx/ui/client/src/helpers/JobTemplates.js @@ -25,6 +25,7 @@ angular.module('JobTemplatesHelper', ['Utilities']) return function(params) { var scope = params.scope, + CredentialList = _.cloneDeep(CredentialList), defaultUrl = GetBasePath('job_templates'), // generator = GenerateForm, form = JobTemplateForm(), diff --git a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js index a405f2bb52..a816cacd3a 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-add.controller.js @@ -13,6 +13,7 @@ form = GroupForm(); // remove "type" field from search options + CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; $scope.formCancel = function(){ diff --git a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js index 094b53399a..b008c0f888 100644 --- a/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js +++ b/awx/ui/client/src/inventories/manage/groups/groups-edit.controller.js @@ -15,6 +15,7 @@ form = GroupForm(); // remove "type" field from search options + CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; $scope.formCancel = function(){ diff --git a/awx/ui/client/src/job-templates/edit/job-templates-edit.controller.js b/awx/ui/client/src/job-templates/edit/job-templates-edit.controller.js index c893463c28..8a2f433dbc 100644 --- a/awx/ui/client/src/job-templates/edit/job-templates-edit.controller.js +++ b/awx/ui/client/src/job-templates/edit/job-templates-edit.controller.js @@ -47,6 +47,7 @@ export default choicesCount = 0; // remove "type" field from search options + CredentialList = _.cloneDeep(CredentialList); CredentialList.fields.kind.noSearch = true; CallbackHelpInit({ scope: $scope }); @@ -471,7 +472,7 @@ export default }); } else { - // job template doesn't exist + // job template doesn't exist $scope.$emit("choicesReady"); } From 86afd6f758e00a21704121300f7e9ff0721f1e0e Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Thu, 14 Jul 2016 15:36:11 -0400 Subject: [PATCH 08/12] Fix NaN / invalid end date value in schedule edit forms (#3007) * fix NAN on end date issue affecting schedule edit form, resolves #2817 * remove debug statement --- .../src/scheduler/schedulerEdit.controller.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/scheduler/schedulerEdit.controller.js b/awx/ui/client/src/scheduler/schedulerEdit.controller.js index 36e94151d3..2687f67ecf 100644 --- a/awx/ui/client/src/scheduler/schedulerEdit.controller.js +++ b/awx/ui/client/src/scheduler/schedulerEdit.controller.js @@ -1,4 +1,20 @@ -export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', function($compile, $state, $stateParams, EditSchedule, Wait, $scope, $rootScope, CreateSelect2, ParseTypeChange) { +export default ['$filter', '$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', +function($filter, $compile, $state, $stateParams, EditSchedule, Wait, $scope, $rootScope, CreateSelect2, ParseTypeChange) { + + $scope.processSchedulerEndDt = function(){ + // set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight + var dt = new Date($scope.schedulerUTCTime); + // increment date by 1 day + dt.setDate(dt.getDate() + 1); + var month = $filter('schZeroPad')(dt.getMonth() + 1, 2), + day = $filter('schZeroPad')(dt.getDate(), 2); + $scope.$parent.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear(); + }; + // initial end @ midnight values + $scope.schedulerEndHour = "00"; + $scope.schedulerEndMinute = "00"; + $scope.schedulerEndSecond = "00"; + $scope.$on("ScheduleFormCreated", function(e, scope) { $scope.hideForm = false; $scope = angular.extend($scope, scope); From 2876bb169b26f7ffaa9d6f50eef72ece9084696b Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 15:49:24 -0400 Subject: [PATCH 09/12] switch order in migration --- awx/main/migrations/0026_v300_credential_unique.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/main/migrations/0026_v300_credential_unique.py b/awx/main/migrations/0026_v300_credential_unique.py index b354ce3d62..3c1d714327 100644 --- a/awx/main/migrations/0026_v300_credential_unique.py +++ b/awx/main/migrations/0026_v300_credential_unique.py @@ -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), From 73722ffb77d8554fd3742fef3d918f7b920e6aec Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Thu, 14 Jul 2016 23:08:02 -0400 Subject: [PATCH 10/12] resolves kickback on #2980 (#3008) --- awx/ui/client/src/helpers/JobDetail.js | 4 ++-- .../src/job-detail/host-events/host-events.controller.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index dde9264109..3b7dcca1ce 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -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) { diff --git a/awx/ui/client/src/job-detail/host-events/host-events.controller.js b/awx/ui/client/src/job-detail/host-events/host-events.controller.js index 55abf51e04..f56111bdb6 100644 --- a/awx/ui/client/src/job-detail/host-events/host-events.controller.js +++ b/awx/ui/client/src/job-detail/host-events/host-events.controller.js @@ -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){ From fc304899bd5d260f06a1447e4dfcadaec87207b3 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Thu, 14 Jul 2016 20:09:46 -0700 Subject: [PATCH 11/12] Jobs list page size (#3019) * changing jobs list page size to 20 by default it was previously set to 10 * adjustment to tag search check for null id --- awx/ui/client/src/controllers/Jobs.js | 2 ++ awx/ui/client/src/search/tagSearch.service.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/controllers/Jobs.js b/awx/ui/client/src/controllers/Jobs.js index 27cbd6f8f5..1e5d4067a7 100644 --- a/awx/ui/client/src/controllers/Jobs.js +++ b/awx/ui/client/src/controllers/Jobs.js @@ -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,6 +78,7 @@ 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' diff --git a/awx/ui/client/src/search/tagSearch.service.js b/awx/ui/client/src/search/tagSearch.service.js index fdd808d3ad..4e5e6ae3ec 100644 --- a/awx/ui/client/src/search/tagSearch.service.js +++ b/awx/ui/client/src/search/tagSearch.service.js @@ -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) { From 8c85035d1835aeef25909a76a9dd66a4a52c53b9 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Thu, 14 Jul 2016 23:10:26 -0400 Subject: [PATCH 12/12] 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) --- awx/ui/client/src/helpers/JobTemplates.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/helpers/JobTemplates.js b/awx/ui/client/src/helpers/JobTemplates.js index 55a4a9aa5f..2947c05546 100644 --- a/awx/ui/client/src/helpers/JobTemplates.js +++ b/awx/ui/client/src/helpers/JobTemplates.js @@ -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() {