diff --git a/awx/conf/license.py b/awx/conf/license.py index 57456f90fa..17a1d323c7 100644 --- a/awx/conf/license.py +++ b/awx/conf/license.py @@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework.exceptions import APIException # Tower -from awx.main.utils.common import get_licenser +from awx.main.utils.common import get_licenser, memoize __all__ = ['LicenseForbids', 'get_license', 'get_licensed_features', 'feature_enabled', 'feature_exists'] @@ -40,6 +40,7 @@ def get_licensed_features(): return features +@memoize(cache_name='ephemeral') def feature_enabled(name): """Return True if the requested feature is enabled, False otherwise.""" validated_license_data = _get_validated_license_data() diff --git a/awx/main/access.py b/awx/main/access.py index 7ab59b8c97..8297d2ba70 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -22,7 +22,7 @@ from awx.main.models import * # noqa from awx.main.models.unified_jobs import ACTIVE_STATES from awx.main.models.mixins import ResourceMixin -from awx.conf.license import LicenseForbids +from awx.conf.license import LicenseForbids, feature_enabled __all__ = ['get_user_queryset', 'check_user_access', 'check_user_access_with_errors', 'user_accessible_objects', 'consumer_access', @@ -311,6 +311,10 @@ class BaseAccess(object): if validation_errors: user_capabilities[display_method] = False continue + elif isinstance(obj, (WorkflowJobTemplate, WorkflowJob)): + if not feature_enabled('workflows'): + user_capabilities[display_method] = (display_method == 'delete') + continue elif display_method == 'copy' and isinstance(obj, WorkflowJobTemplate) and obj.organization_id is None: user_capabilities[display_method] = self.user.is_superuser continue diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index c8c382472a..e62d2274c4 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -107,13 +107,14 @@ class RequireDebugTrueOrTest(logging.Filter): return settings.DEBUG or 'test' in sys.argv -def memoize(ttl=60, cache_key=None): +def memoize(ttl=60, cache_key=None, cache_name='default'): ''' Decorator to wrap a function and cache its result. ''' - from django.core.cache import cache + from django.core.cache import caches def _memoizer(f, *args, **kwargs): + cache = caches[cache_name] key = cache_key or slugify('%s %r %r' % (f.__name__, args, kwargs)) value = cache.get(key) if value is None: diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index c4af5d8d10..514b6ac731 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -481,6 +481,9 @@ if is_testing(): 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', }, + 'ephemeral': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + }, } else: CACHES = { @@ -488,6 +491,9 @@ else: 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'memcached:11211', }, + 'ephemeral': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + }, } # Social Auth configuration.