Revamp user_capabilities with new copy fields

Add copy fields corresponding to new server-side copying

Refactor the way user_capabilities are delivered
 - move the prefetch definition from views to serializer
 - store temporary mapping in serializer context
 - use serializer backlinks to denote polymorphic prefetch model exclusions
This commit is contained in:
AlanCoding
2018-02-22 15:27:24 -05:00
parent 9493b72f29
commit ce9234df0f
6 changed files with 111 additions and 75 deletions

View File

@@ -32,6 +32,7 @@ from django.db import DatabaseError
from django.utils.translation import ugettext_lazy as _
from django.db.models.fields.related import ForeignObjectRel, ManyToManyField
from django.db.models.query import QuerySet
from django.db.models import Q
# Django REST Framework
from rest_framework.exceptions import ParseError, PermissionDenied
@@ -44,7 +45,7 @@ logger = logging.getLogger('awx.main.utils')
__all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore', 'memoize', 'memoize_delete',
'get_ansible_version', 'get_ssh_version', 'get_licenser', 'get_awx_version', 'update_scm_url',
'get_type_for_model', 'get_model_for_type', 'copy_model_by_class',
'copy_m2m_relationships', 'cache_list_capabilities', 'to_python_boolean',
'copy_m2m_relationships', 'prefetch_page_capabilities', 'to_python_boolean',
'ignore_inventory_computed_fields', 'ignore_inventory_group_removal',
'_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided',
'get_current_apps', 'set_current_apps', 'OutputEventFilter',
@@ -503,7 +504,6 @@ def get_model_for_type(type):
'''
Return model class for a given type name.
'''
from django.db.models import Q
from django.contrib.contenttypes.models import ContentType
for ct in ContentType.objects.filter(Q(app_label='main') | Q(app_label='auth', model='user')):
ct_model = ct.model_class()
@@ -516,30 +516,31 @@ def get_model_for_type(type):
raise DatabaseError('"{}" is not a valid AWX model.'.format(type))
def cache_list_capabilities(page, prefetch_list, model, user):
def prefetch_page_capabilities(model, page, prefetch_list, user):
'''
Given a `page` list of objects, the specified roles for the specified user
are save on each object in the list, using 1 query for each role type
Given a `page` list of objects, a nested dictionary of user_capabilities
are returned by id, ex.
{
4: {'edit': True, 'start': True},
6: {'edit': False, 'start': False}
}
Each capability is produced for all items in the page in a single query
Examples:
capabilities_prefetch = ['admin', 'execute']
Examples of prefetch language:
prefetch_list = ['admin', 'execute']
--> prefetch the admin (edit) and execute (start) permissions for
items in list for current user
capabilities_prefetch = ['inventory.admin']
prefetch_list = ['inventory.admin']
--> prefetch the related inventory FK permissions for current user,
and put it into the object's cache
capabilities_prefetch = [{'copy': ['inventory.admin', 'project.admin']}]
prefetch_list = [{'copy': ['inventory.admin', 'project.admin']}]
--> prefetch logical combination of admin permission to inventory AND
project, put into cache dictionary as "copy"
'''
from django.db.models import Q
page_ids = [obj.id for obj in page]
mapping = {}
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()
mapping[obj.id] = {}
for prefetch_entry in prefetch_list:
@@ -583,11 +584,9 @@ 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
mapping[obj.pk][display_method] = bool(obj.pk in ids_with_role)
return mapping
def validate_vars_type(vars_obj):