mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 01:17:37 -02:30
JT OPTIONS based on RBAC, refactoring toward combinational prefetching
This commit is contained in:
@@ -2544,6 +2544,7 @@ class LabelSerializer(BaseSerializer):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
class ScheduleSerializer(BaseSerializer):
|
class ScheduleSerializer(BaseSerializer):
|
||||||
|
show_capabilities = ['edit', 'delete']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Schedule
|
model = Schedule
|
||||||
|
|||||||
@@ -222,8 +222,8 @@ class BaseAccess(object):
|
|||||||
def get_user_capabilities(self, obj, method_list):
|
def get_user_capabilities(self, obj, method_list):
|
||||||
user_capabilities = {}
|
user_capabilities = {}
|
||||||
|
|
||||||
|
# Custom ordering to loop through methods so we can reuse earlier calcs
|
||||||
for display_method in ['edit', 'delete', 'start', 'schedule', 'copy', 'adhoc']:
|
for display_method in ['edit', 'delete', 'start', 'schedule', 'copy', 'adhoc']:
|
||||||
# Custom ordering of methods used so we can reuse earlier calcs
|
|
||||||
if display_method not in method_list:
|
if display_method not in method_list:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -233,54 +233,38 @@ class BaseAccess(object):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Aliases for going form UI language to API language
|
# Aliases for going form UI language to API language
|
||||||
# speedups in certain cases by deferring to earlier property
|
|
||||||
if display_method == 'edit':
|
if display_method == 'edit':
|
||||||
method = 'change'
|
method = 'change'
|
||||||
elif display_method == 'copy':
|
elif display_method == 'copy':
|
||||||
method = 'add'
|
method = 'add'
|
||||||
elif display_method == 'schedule' and 'edit' in user_capabilities:
|
|
||||||
user_capabilities['schedule'] = user_capabilities['edit']
|
|
||||||
continue
|
|
||||||
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob)):
|
|
||||||
user_capabilities['delete'] = user_capabilities['edit']
|
|
||||||
continue
|
|
||||||
elif display_method == 'adhoc':
|
elif display_method == 'adhoc':
|
||||||
method = 'run_ad_hoc_commands'
|
method = 'run_ad_hoc_commands'
|
||||||
else:
|
else:
|
||||||
method = display_method
|
method = display_method
|
||||||
|
|
||||||
|
# Shortcuts in certain cases by deferring to earlier property
|
||||||
|
if display_method == 'schedule' and 'edit' in user_capabilities:
|
||||||
|
user_capabilities['schedule'] = user_capabilities['edit']
|
||||||
|
continue
|
||||||
|
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob)):
|
||||||
|
user_capabilities['delete'] = user_capabilities['edit']
|
||||||
|
continue
|
||||||
|
|
||||||
# Preprocessing before the access method is called
|
# Preprocessing before the access method is called
|
||||||
data = None
|
data = None
|
||||||
if method == 'add':
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
access_instance = self
|
|
||||||
obj_check = obj
|
|
||||||
if isinstance(obj, (Group, Host)):
|
|
||||||
if method == 'start':
|
|
||||||
if obj.inventory_source:
|
|
||||||
obj_check = obj.inventory_source
|
|
||||||
else:
|
|
||||||
user_capabilities[method] = False
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
obj_check = obj.inventory
|
|
||||||
access_class = access_registry.get(type(obj_check), [])[0]
|
|
||||||
access_instance = access_class(self.user)
|
|
||||||
if isinstance(obj, JobTemplate):
|
if isinstance(obj, JobTemplate):
|
||||||
data = {'reference_obj': obj}
|
data = {'reference_obj': obj}
|
||||||
|
elif method == 'add':
|
||||||
|
data = {}
|
||||||
|
|
||||||
# try:
|
# Compute permission
|
||||||
access_method = getattr(access_instance, "can_%s" % method)
|
access_method = getattr(self, "can_%s" % method)
|
||||||
if method in ['change']: # 3 args
|
if method in ['change']: # 3 args
|
||||||
user_capabilities[display_method] = access_method(obj_check, data)
|
user_capabilities[display_method] = access_method(obj, data)
|
||||||
elif method in ['delete', 'start', 'run_ad_hoc_commands']: # 2 args
|
elif method in ['delete', 'start', 'run_ad_hoc_commands']: # 2 args
|
||||||
user_capabilities[display_method] = access_method(obj_check)
|
user_capabilities[display_method] = access_method(obj)
|
||||||
elif method in ['add']: # 2 args with data
|
elif method in ['add']: # 2 args with data
|
||||||
user_capabilities[display_method] = access_method(data)
|
user_capabilities[display_method] = access_method(data)
|
||||||
# except Exception as exc:
|
|
||||||
# user_capabilities[display_method] = False
|
|
||||||
# print(exc)
|
|
||||||
|
|
||||||
return user_capabilities
|
return user_capabilities
|
||||||
|
|
||||||
@@ -603,6 +587,12 @@ class GroupAccess(BaseAccess):
|
|||||||
"active_jobs": active_jobs})
|
"active_jobs": active_jobs})
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def can_start(self, obj):
|
||||||
|
# Used as another alias to inventory_source start access
|
||||||
|
if obj and obj.inventory_source:
|
||||||
|
return self.user.can_access(InventorySource, 'start', obj.inventory_source)
|
||||||
|
return False
|
||||||
|
|
||||||
class InventorySourceAccess(BaseAccess):
|
class InventorySourceAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see inventory sources whenever I can see their group or inventory.
|
I can see inventory sources whenever I can see their group or inventory.
|
||||||
@@ -938,7 +928,9 @@ class JobTemplateAccess(BaseAccess):
|
|||||||
Users who are able to create deploy jobs can also run normal and check (dry run) jobs.
|
Users who are able to create deploy jobs can also run normal and check (dry run) jobs.
|
||||||
'''
|
'''
|
||||||
if not data: # So the browseable API will work
|
if not data: # So the browseable API will work
|
||||||
return True
|
return (
|
||||||
|
Project.accessible_objects(self.user, 'use_role').exists() or
|
||||||
|
Inventory.accessible_objects(self.user, 'use_role').exists())
|
||||||
|
|
||||||
# if reference_obj is provided, determine if it can be coppied
|
# if reference_obj is provided, determine if it can be coppied
|
||||||
reference_obj = data.pop('reference_obj', None)
|
reference_obj = data.pop('reference_obj', None)
|
||||||
|
|||||||
@@ -416,6 +416,9 @@ def cache_list_capabilities(page, role_types, model, user):
|
|||||||
'''
|
'''
|
||||||
page_ids = [obj.id for obj in page]
|
page_ids = [obj.id for obj in page]
|
||||||
id_lists = {}
|
id_lists = {}
|
||||||
|
for obj in page:
|
||||||
|
obj.capabilities_cache = {}
|
||||||
|
|
||||||
for role_type in role_types:
|
for role_type in role_types:
|
||||||
# Role name translation to UI names for methods
|
# Role name translation to UI names for methods
|
||||||
display_method = role_type
|
display_method = role_type
|
||||||
@@ -423,14 +426,15 @@ def cache_list_capabilities(page, role_types, model, user):
|
|||||||
display_method = 'edit'
|
display_method = 'edit'
|
||||||
elif role_type in ['execute', 'update']:
|
elif role_type in ['execute', 'update']:
|
||||||
display_method = 'start'
|
display_method = 'start'
|
||||||
|
|
||||||
# Query for union of page objects & role accessible_objects
|
# Query for union of page objects & role accessible_objects
|
||||||
id_lists[display_method] = model.accessible_objects(
|
ids_with_role = set(model.accessible_objects(
|
||||||
user, '%s_role' % role_type).filter(pk__in=page_ids).values_list('pk', flat=True)
|
user, '%s_role' % role_type).filter(pk__in=page_ids).values_list('pk', flat=True))
|
||||||
# Save data item-by-item
|
|
||||||
for obj in page:
|
# Save data item-by-item
|
||||||
obj.capabilities_cache = {display_method: False for display_method in id_lists.keys()}
|
for obj in page:
|
||||||
for display_method, id_list in id_lists.iteritems():
|
obj.capabilities_cache[display_method] = False
|
||||||
if obj.pk in id_list:
|
if obj.pk in ids_with_role:
|
||||||
obj.capabilities_cache[display_method] = True
|
obj.capabilities_cache[display_method] = True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user