130 lines
4.4 KiB
Python
130 lines
4.4 KiB
Python
# Decorating URL includes, <https://djangosnippets.org/snippets/2532/>
|
|
|
|
from functools import wraps
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth.decorators import user_passes_test
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
|
|
from django.views.debug import technical_404_response
|
|
from django.http import Http404
|
|
|
|
class DecoratedURLPattern(RegexURLPattern):
|
|
def resolve(self, *args, **kwargs):
|
|
result = super(DecoratedURLPattern, self).resolve(*args, **kwargs)
|
|
if result:
|
|
result.func = self._decorate_with(result.func)
|
|
return result
|
|
|
|
class DecoratedRegexURLResolver(RegexURLResolver):
|
|
def resolve(self, *args, **kwargs):
|
|
result = super(DecoratedRegexURLResolver, self).resolve(*args, **kwargs)
|
|
if result:
|
|
result.func = self._decorate_with(result.func)
|
|
return result
|
|
|
|
def decorated_includes(func, includes, *args, **kwargs):
|
|
urlconf_module, app_name, namespace = includes
|
|
|
|
for item in urlconf_module:
|
|
if isinstance(item, RegexURLPattern):
|
|
item.__class__ = DecoratedURLPattern
|
|
item._decorate_with = func
|
|
|
|
elif isinstance(item, RegexURLResolver):
|
|
item.__class__ = DecoratedRegexURLResolver
|
|
item._decorate_with = func
|
|
|
|
return urlconf_module, app_name, namespace
|
|
|
|
|
|
# below, a set of decorators to generate urls.py like this:
|
|
# urlpatterns = required(
|
|
# app_enabled('applabel'),
|
|
# [... urls for applabel ...]
|
|
# )
|
|
|
|
def unless(test, message):
|
|
'''Decorator returning a 404 status code if some condition is not met'''
|
|
def decorator(func):
|
|
@wraps(func)
|
|
def f(request, *args, **kwargs):
|
|
if not test():
|
|
return technical_404_response(request, Http404(message))
|
|
return func(request, *args, **kwargs)
|
|
return f
|
|
return decorator
|
|
|
|
def app_enabled(app_label):
|
|
'''for enabling a view based on PASSERELLE_APP_<APP_LABEL>_ENABLED flag'''
|
|
def test():
|
|
return getattr(settings, 'PASSERELLE_APP_%s_ENABLED' % app_label.upper(), True)
|
|
return unless(test, 'please enable %s' % app_label)
|
|
|
|
def setting_enabled(name):
|
|
'''for enabling a view based on a setting'''
|
|
def test():
|
|
return getattr(settings, name, False)
|
|
return unless(test, 'please enable %s' % name)
|
|
|
|
# code bellow is borrowed from https://djangosnippets.org/snippets/2607/
|
|
# or https://gist.github.com/sjzabel/1378003
|
|
def required(wrapping_functions,patterns_rslt):
|
|
'''
|
|
Used to require 1..n decorators in any view returned by a url tree
|
|
|
|
Usage:
|
|
urlpatterns = required(func,[...urls...])
|
|
urlpatterns = required((func,func,func),[...urls...])
|
|
|
|
Note:
|
|
Use functools.partial to pass keyword params to the required
|
|
decorators. If you need to pass args you will have to write a
|
|
wrapper function.
|
|
|
|
Example:
|
|
from functools import partial
|
|
|
|
urlpatterns = required(
|
|
partial(login_required,login_url='/accounts/login/'),
|
|
[...urls...]
|
|
)
|
|
'''
|
|
if not hasattr(wrapping_functions, '__iter__'):
|
|
wrapping_functions = (wrapping_functions, )
|
|
|
|
return [
|
|
_wrap_instance__resolve(wrapping_functions, instance)
|
|
for instance in patterns_rslt
|
|
]
|
|
|
|
def _wrap_instance__resolve(wrapping_functions, instance):
|
|
def _wrap_func_in_returned_resolver_match(*args, **kwargs):
|
|
rslt = resolve(*args, **kwargs)
|
|
if not hasattr(rslt, 'func'):
|
|
return rslt
|
|
f = getattr(rslt, 'func')
|
|
for _f in reversed(wrapping_functions):
|
|
# @decorate the function from inner to outter
|
|
f = _f(f)
|
|
setattr(rslt, 'func', f)
|
|
return rslt
|
|
if not hasattr(instance, 'resolve'):
|
|
return instance
|
|
resolve = getattr(instance, 'resolve')
|
|
setattr(instance, 'resolve', _wrap_func_in_returned_resolver_match)
|
|
return instance
|
|
|
|
def manager_required(function=None, login_url=None):
|
|
def check_manager(user):
|
|
if user and user.is_staff:
|
|
return True
|
|
if user and not user.is_anonymous():
|
|
raise PermissionDenied()
|
|
# As the last resort, show the login form
|
|
return False
|
|
actual_decorator = user_passes_test(check_manager, login_url=login_url)
|
|
if function:
|
|
return actual_decorator(function)
|
|
return actual_decorator
|