From 21d3051ec4c7692fac85bacd2931275b6715fbb1 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Thu, 18 Aug 2016 15:14:31 -0400 Subject: [PATCH] Include user edit/start/delete/copy capabilities to summary fields This patch generically adds a map of capabilities that the current user has on an object, namely can they start, delete, editor, or copy the object. The intent is that these flags will be used by the UI to disable buttons that do those things. #2479 --- awx/api/serializers.py | 7 +++++++ awx/main/access.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index af3e6ae4ac..acc0b48e8e 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -37,6 +37,7 @@ from polymorphic import PolymorphicModel # AWX from awx.main.constants import SCHEDULEABLE_PROVIDERS from awx.main.models import * # noqa +from awx.main.access import get_user_capabilities from awx.main.fields import ImplicitRoleField from awx.main.utils import get_type_for_model, get_model_for_type, build_url, timestamp_apiformat, camelcase_to_underscore, getattrd from awx.main.conf import tower_settings @@ -330,6 +331,12 @@ class BaseSerializer(serializers.ModelSerializer): } if len(roles) > 0: summary_fields['object_roles'] = roles + view = self.context.get('view', None) + if view and view.request and view.request.user: + user_capabilities = get_user_capabilities(view.request.user, obj) + if user_capabilities: + summary_fields['user_capabilities'] = user_capabilities + return summary_fields def get_created(self, obj): diff --git a/awx/main/access.py b/awx/main/access.py index e5ca8fa0ec..3dfc777d5f 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -116,6 +116,18 @@ def check_user_access(user, model_class, action, *args, **kwargs): return result return False +def get_user_capabilities(user, instance): + ''' + Returns a dictionary of capabilities the user has on the particular + instance. *NOTE* This is not a direct mapping of can_* methods into this + dictionary, it is intended to munge some queries in a way that is + convenient for the user interface to consume and hide or show various + actions in the interface. + ''' + for access_class in access_registry.get(type(instance), []): + return access_class(user).get_user_capabilities(instance) + return None + def check_superuser(func): ''' check_superuser is a decorator that provides a simple short circuit @@ -207,6 +219,28 @@ class BaseAccess(object): elif "features" not in validation_info: raise LicenseForbids("Features not found in active license.") + def get_user_capabilities(self, obj): + user_capabilities = {} + + if isinstance(obj, JobTemplate): + user_capabilities['copy'] = self.user.can_access(type(obj), 'add', { 'reference_obj': obj }) + print(type(obj)) + + for method in ['change', 'delete', 'start']: + try: + if isinstance(obj, Group) and method is 'start' and obj.inventory_source: + obj = obj.inventory_source + + if method in ['change']: # 3 args + user_capabilities[method] = self.user.can_access(type(obj), method, obj, {}) + else: # 2 args + user_capabilities[method] = self.user.can_access(type(obj), method, obj) + except Exception as exc: + user_capabilities[method] = False + print(exc) + + return user_capabilities + class UserAccess(BaseAccess): '''