From d054f866527c9d7bb4905e05b32372d792330617 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Tue, 14 Feb 2017 11:35:58 -0500 Subject: [PATCH] update organization counts to correspond with UI lists --- awx/api/views.py | 39 ++++++++++--------- .../api/test_organization_counts.py | 23 +++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index 56d5e7d789..ccd45916d5 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -22,7 +22,7 @@ from django.contrib.auth.models import User, AnonymousUser from django.core.cache import cache from django.core.urlresolvers import reverse from django.core.exceptions import FieldError -from django.db.models import Q, Count +from django.db.models import Q, Count, F from django.db import IntegrityError, transaction, connection from django.shortcuts import get_object_or_404 from django.utils.encoding import smart_text, force_text @@ -646,15 +646,16 @@ class OrganizationCountsMixin(object): self.request.user, 'read_role').values('organization').annotate( Count('organization')).order_by('organization') - JT_reference = 'project__organization' - db_results['job_templates'] = JobTemplate.accessible_objects( - self.request.user, 'read_role').exclude(job_type='scan').values(JT_reference).annotate( - Count(JT_reference)).order_by(JT_reference) + JT_project_reference = 'project__organization' + JT_inventory_reference = 'inventory__organization' + db_results['job_templates_project'] = JobTemplate.accessible_objects( + self.request.user, 'read_role').exclude( + project__organization=F(JT_inventory_reference)).values(JT_project_reference).annotate( + Count(JT_project_reference)).order_by(JT_project_reference) - JT_scan_reference = 'inventory__organization' - db_results['job_templates_scan'] = JobTemplate.accessible_objects( - self.request.user, 'read_role').filter(job_type='scan').values(JT_scan_reference).annotate( - Count(JT_scan_reference)).order_by(JT_scan_reference) + db_results['job_templates_inventory'] = JobTemplate.accessible_objects( + self.request.user, 'read_role').values(JT_inventory_reference).annotate( + Count(JT_inventory_reference)).order_by(JT_inventory_reference) db_results['projects'] = project_qs\ .values('organization').annotate(Count('organization')).order_by('organization') @@ -672,16 +673,16 @@ class OrganizationCountsMixin(object): 'inventories': 0, 'teams': 0, 'users': 0, 'job_templates': 0, 'admins': 0, 'projects': 0} - for res in db_results: - if res == 'job_templates': - org_reference = JT_reference - elif res == 'job_templates_scan': - org_reference = JT_scan_reference + for res, count_qs in db_results.items(): + if res == 'job_templates_project': + org_reference = JT_project_reference + elif res == 'job_templates_inventory': + org_reference = JT_inventory_reference elif res == 'users': org_reference = 'id' else: org_reference = 'organization' - for entry in db_results[res]: + for entry in count_qs: org_id = entry[org_reference] if org_id in count_context: if res == 'users': @@ -690,11 +691,13 @@ class OrganizationCountsMixin(object): continue count_context[org_id][res] = entry['%s__count' % org_reference] - # Combine the counts for job templates with scan job templates + # Combine the counts for job templates by project and inventory for org in org_id_list: org_id = org['id'] - if 'job_templates_scan' in count_context[org_id]: - count_context[org_id]['job_templates'] += count_context[org_id].pop('job_templates_scan') + count_context[org_id]['job_templates'] = 0 + for related_path in ['job_templates_project', 'job_templates_inventory']: + if related_path in count_context[org_id]: + count_context[org_id]['job_templates'] += count_context[org_id].pop(related_path) full_context['related_field_counts'] = count_context diff --git a/awx/main/tests/functional/api/test_organization_counts.py b/awx/main/tests/functional/api/test_organization_counts.py index 500667e107..f08fd75d01 100644 --- a/awx/main/tests/functional/api/test_organization_counts.py +++ b/awx/main/tests/functional/api/test_organization_counts.py @@ -181,6 +181,29 @@ def test_scan_JT_counted(resourced_organization, user, get): assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict +@pytest.mark.django_db +def test_JT_not_double_counted(resourced_organization, user, get): + admin_user = user('admin', True) + # Add a scan job template to the org + resourced_organization.projects.all()[0].jobtemplates.create( + job_type='run', + inventory=resourced_organization.inventories.all()[0], + project=resourced_organization.projects.all()[0], + name='double-linked-job-template') + counts_dict = COUNTS_PRIMES + counts_dict['job_templates'] += 1 + + # Test list view + list_response = get(reverse('api:organization_list', args=[]), admin_user) + assert list_response.status_code == 200 + assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict + + # Test detail view + detail_response = get(reverse('api:organization_detail', args=[resourced_organization.pk]), admin_user) + assert detail_response.status_code == 200 + assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict + + @pytest.mark.django_db def test_JT_associated_with_project(organizations, project, user, get): # Check that adding a project to an organization gets the project's JT