From 7967cc77220ea1d29a31d8434661ef52d1bcd840 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Fri, 3 Feb 2017 23:19:05 -0500 Subject: [PATCH] force UJT user_capabilities to be correct for all submodels --- awx/api/views.py | 4 ++-- awx/main/access.py | 1 + awx/main/models/unified_jobs.py | 6 +++++ .../functional/api/test_rbac_displays.py | 22 +++++++++++++++++-- awx/main/utils/common.py | 6 +++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index 0f75d6ca61..9b6561e827 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2569,8 +2569,8 @@ class JobTemplateLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDeta del request.data['name'] del request.data['organization'] if Label.objects.filter(unifiedjobtemplate_labels=self.kwargs['pk']).count() > 100: - return Response(dict(msg=_('Maximum labels limit for a job template reached.')), - status=status.HTTP_400_BAD_REQUEST) + return Response(dict(msg=_('Maximum number of labels for {} reached.'.format( + self.parent_model._meta.verbose_name_raw))), status=status.HTTP_400_BAD_REQUEST) return super(JobTemplateLabelList, self).post(request, *args, **kwargs) diff --git a/awx/main/access.py b/awx/main/access.py index 5adb4649ed..ad40a3dafe 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -1916,6 +1916,7 @@ class UnifiedJobAccess(BaseAccess): 'modified_by', 'unified_job_node__workflow_job', 'unified_job_template', + Prefetch('labels', queryset=Label.objects.all().order_by('name')) ) # WISH - sure would be nice if the following worked, but it does not. diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 7a7275a1fb..7da004eb7e 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -168,6 +168,12 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio else: return super(UnifiedJobTemplate, self).unique_error_message(model_class, unique_check) + @classmethod + def invalid_user_capabilities_prefetch_models(cls): + if cls != UnifiedJobTemplate: + return [] + return ['project', 'inventorysource', 'systemjobtemplate'] + @classmethod def accessible_pk_qs(cls, accessor, role_field): ''' diff --git a/awx/main/tests/functional/api/test_rbac_displays.py b/awx/main/tests/functional/api/test_rbac_displays.py index e1255ffea9..c0a3e463cf 100644 --- a/awx/main/tests/functional/api/test_rbac_displays.py +++ b/awx/main/tests/functional/api/test_rbac_displays.py @@ -3,8 +3,7 @@ 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.models import Role, Group, UnifiedJobTemplate, JobTemplate from awx.main.access import ( access_registry, get_user_capabilities @@ -283,6 +282,25 @@ def test_prefetch_jt_capabilities(job_template, rando): assert qs[0].capabilities_cache == {'edit': False, 'start': True} +@pytest.mark.django_db +def test_prefetch_ujt_job_template_capabilities(alice, bob, job_template): + job_template.execute_role.members.add(alice) + qs = UnifiedJobTemplate.objects.all() + cache_list_capabilities(qs, ['admin', 'execute'], UnifiedJobTemplate, alice) + assert qs[0].capabilities_cache == {'edit': False, 'start': True} + qs = UnifiedJobTemplate.objects.all() + cache_list_capabilities(qs, ['admin', 'execute'], UnifiedJobTemplate, bob) + assert qs[0].capabilities_cache == {'edit': False, 'start': False} + + +@pytest.mark.django_db +def test_prefetch_ujt_project_capabilities(alice, project): + project.update_role.members.add(alice) + qs = UnifiedJobTemplate.objects.all() + cache_list_capabilities(qs, ['admin', 'execute'], UnifiedJobTemplate, alice) + assert qs[0].capabilities_cache == {} + + @pytest.mark.django_db def test_prefetch_group_capabilities(group, rando): group.inventory.adhoc_role.members.add(rando) diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 5e70b7f446..0378842532 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -519,6 +519,10 @@ def cache_list_capabilities(page, prefetch_list, model, user): for obj in page: obj.capabilities_cache = {} + skip_models = [] + if hasattr(model, 'invalid_user_capabilities_prefetch_models'): + skip_models = model.invalid_user_capabilities_prefetch_models() + for prefetch_entry in prefetch_list: display_method = None @@ -561,6 +565,8 @@ def cache_list_capabilities(page, prefetch_list, model, user): # Save data item-by-item for obj in page: + if skip_models and obj.__class__.__name__.lower() in skip_models: + continue obj.capabilities_cache[display_method] = False if obj.pk in ids_with_role: obj.capabilities_cache[display_method] = True