1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

job template serializer can_add calc to avoid lookups of known related objects

This commit is contained in:
AlanCoding 2016-06-24 17:25:10 -04:00
parent 358f267e14
commit 7b0f20e90d
3 changed files with 33 additions and 27 deletions

View File

@ -23,7 +23,6 @@ from django.db import models
# from django.utils.translation import ugettext_lazy as _ # from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.text import capfirst from django.utils.text import capfirst
from django.forms.models import model_to_dict
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
@ -1861,9 +1860,8 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
d['can_copy'] = not validation_errors d['can_copy'] = not validation_errors
d['can_edit'] = True d['can_edit'] = True
else: else:
jt_data = model_to_dict(obj) d['can_copy'] = (not validation_errors) and request.user.can_access(JobTemplate, 'add', {"reference_obj": obj})
d['can_copy'] = (not validation_errors) and request.user.can_access(JobTemplate, 'add', jt_data) d['can_edit'] = request.user.can_access(JobTemplate, 'change', obj, {})
d['can_edit'] = request.user.can_access(JobTemplate, 'change', obj, jt_data)
d['recent_jobs'] = self._recent_jobs(obj) d['recent_jobs'] = self._recent_jobs(obj)
return d return d

View File

@ -788,6 +788,9 @@ class JobTemplateAccess(BaseAccess):
if not data or '_method' in data: # So the browseable API will work? if not data or '_method' in data: # So the browseable API will work?
return True return True
# if reference_obj is provided, determine if it can be coppied
reference_obj = data.pop('reference_obj', None)
if 'job_type' in data and data['job_type'] == PERM_INVENTORY_SCAN: if 'job_type' in data and data['job_type'] == PERM_INVENTORY_SCAN:
self.check_license(feature='system_tracking') self.check_license(feature='system_tracking')
@ -797,51 +800,54 @@ class JobTemplateAccess(BaseAccess):
if self.user.is_superuser: if self.user.is_superuser:
return True return True
def get_value(Class, field):
if reference_obj:
return getattr(reference_obj, field, None)
else:
pk = get_pk_from_dict(data, field)
if pk:
return get_object_or_400(Class, pk=pk)
else:
return None
# If a credential is provided, the user should have use access to it. # If a credential is provided, the user should have use access to it.
credential_pk = get_pk_from_dict(data, 'credential') credential = get_value(Credential, 'credential')
if credential_pk: if credential:
credential = get_object_or_400(Credential, pk=credential_pk)
if self.user not in credential.use_role: if self.user not in credential.use_role:
return False return False
# If a cloud credential is provided, the user should have use access. # If a cloud credential is provided, the user should have use access.
cloud_credential_pk = get_pk_from_dict(data, 'cloud_credential') cloud_credential = get_value(Credential, 'cloud_credential')
if cloud_credential_pk: if cloud_credential:
cloud_credential = get_object_or_400(Credential,
pk=cloud_credential_pk)
if self.user not in cloud_credential.use_role: if self.user not in cloud_credential.use_role:
return False return False
# If a network credential is provided, the user should have use access. # If a network credential is provided, the user should have use access.
network_credential_pk = get_pk_from_dict(data, 'network_credential') network_credential = get_value(Credential, 'network_credential')
if network_credential_pk: if network_credential:
network_credential = get_object_or_400(Credential,
pk=network_credential_pk)
if self.user not in network_credential.use_role: if self.user not in network_credential.use_role:
return False return False
# If an inventory is provided, the user should have use access. # If an inventory is provided, the user should have use access.
inventory_pk = get_pk_from_dict(data, 'inventory') inventory = get_value(Inventory, 'inventory')
if inventory_pk: if inventory:
inventory = get_object_or_400(Inventory, pk=inventory_pk)
if self.user not in inventory.use_role: if self.user not in inventory.use_role:
return False return False
project_pk = get_pk_from_dict(data, 'project') project = get_value(Project, 'project')
if 'job_type' in data and data['job_type'] == PERM_INVENTORY_SCAN: if 'job_type' in data and data['job_type'] == PERM_INVENTORY_SCAN:
if inventory_pk and inventory.organization: if inventory:
org = inventory.organization org = inventory.organization
accessible = self.user in org.admin_role accessible = self.user in org.admin_role
else: else:
accessible = False accessible = False
if not project_pk and accessible: if not project and accessible:
return True return True
elif not accessible: elif not accessible:
return False return False
# If the user has admin access to the project (as an org admin), should # If the user has admin access to the project (as an org admin), should
# be able to proceed without additional checks. # be able to proceed without additional checks.
if project_pk: if project:
project = get_object_or_400(Project, pk=project_pk)
return self.user in project.use_role return self.user in project.use_role
else: else:
return False return False

View File

@ -195,7 +195,7 @@ def test_org_admin_foreign_cred_no_copy_edit(jt_copy_edit, org_admin, machine_cr
""" """
Organization admins without access to the 3 related resources: Organization admins without access to the 3 related resources:
SHOULD NOT be able to copy JT SHOULD NOT be able to copy JT
SHOULD NOT be able to edit that job template SHOULD be able to edit that job template, for nonsensitive changes
""" """
# Attach credential to JT that org admin can not use # Attach credential to JT that org admin can not use
@ -209,11 +209,13 @@ def test_org_admin_foreign_cred_no_copy_edit(jt_copy_edit, org_admin, machine_cr
serializer.context['request'] = request serializer.context['request'] = request
response = serializer.to_representation(jt_copy_edit) response = serializer.to_representation(jt_copy_edit)
assert not response['summary_fields']['can_copy'] assert not response['summary_fields']['can_copy']
assert not response['summary_fields']['can_edit'] assert response['summary_fields']['can_edit']
@pytest.mark.django_db @pytest.mark.django_db
def test_jt_admin_copy_edit(jt_copy_edit, rando): def test_jt_admin_copy_edit(jt_copy_edit, rando):
"JT admins wihout access to associated resources SHOULD NOT be able to copy" """
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 # random user given JT admin access only
jt_copy_edit.admin_role.members.add(rando) jt_copy_edit.admin_role.members.add(rando)
@ -226,7 +228,7 @@ def test_jt_admin_copy_edit(jt_copy_edit, rando):
serializer.context['request'] = request serializer.context['request'] = request
response = serializer.to_representation(jt_copy_edit) response = serializer.to_representation(jt_copy_edit)
assert not response['summary_fields']['can_copy'] assert not response['summary_fields']['can_copy']
assert not response['summary_fields']['can_edit'] assert response['summary_fields']['can_edit']
@pytest.mark.django_db @pytest.mark.django_db
def test_proj_jt_admin_copy_edit(jt_copy_edit, rando): def test_proj_jt_admin_copy_edit(jt_copy_edit, rando):