Skip to content

Instantly share code, notes, and snippets.

@rj76
Created June 29, 2021 19:19
Show Gist options
  • Save rj76/6e19cdf0f3b8a09720765b54aafe9c08 to your computer and use it in GitHub Desktop.
Save rj76/6e19cdf0f3b8a09720765b54aafe9c08 to your computer and use it in GitHub Desktop.
Django templatetag ACL implementation
# templatetags
from django import template
from apps.core import utils
register = template.Library()
module_paths_text = None
modules = {}
@register.filter(name='member_has_access_to_module', takes_context=True)
def member_has_access_to_module(context, module_path):
global module_paths_text, modules
user = context['request'].user
# cache database lookup
if not module_paths_text:
module_paths_text = context['request'].session['member'].contract.module_paths_text
# cache modules
if not modules:
modules = get_contract_modules(module_paths_text)
return utils.member_has_access_to_module(user, module_path, modules=modules)
@register.filter(name='usertypes_required', takes_context=True)
def usertypes_required(context, usertypes):
user = context['request'].user
return utils.usertypes_required(user, usertypes)
# apps.core.utils
def member_has_access_to_module(user, module_path, module_paths_text=None, modules=None):
# staff and superusers always have access
if user.is_staff or user.is_superuser:
return True
if not modules and module_paths_text:
modules = get_contract_modules(module_paths_text)
# module part check (e.g. orders:orders)
if ':' in module_path:
module, path = module_path.split(':')
return path in modules[module]
# only a module check
return module_path in modules
def get_contract_modules(module_paths_text):
modules = {}
paths = module_paths_text.split('|')
for path in paths:
_module_name, parts = path.split(':')
for part in parts.split(','):
modules[_module_name.lower()] = part.lower()
return modules
def usertypes_required(user, usertypes):
# staff and superusers always have access
if user.is_staff or user.is_superuser:
return True
for usertype in usertypes.split(','):
if getattr(user, usertype):
return True
return False
# test_utils.py
def get_user(is_staff=False, is_superuser=False, is_planning_user=False, is_sales_user=False, is_customer_user=False):
class User:
def __init__(self, is_staff, is_superuser, is_planning_user, is_sales_user, is_customer_user):
self.is_staff = is_staff
self.is_superuser = is_superuser
self.planning_user = is_planning_user
self.sales_user = is_sales_user
self.customer_user = is_customer_user
return User(is_staff, is_superuser, is_planning_user, is_sales_user, is_customer_user)
def test_member_has_access_to_module_normal_user():
user = get_user()
module_path = 'orders'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_member_has_access_to_module_path_normal_user():
user = get_user()
module_path = 'mobile:stats'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_member_no_access_to_module_normal_user():
user = get_user()
module_path = 'inventory'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert not utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_member_no_access_to_module_path_normal_user():
user = get_user()
module_path = 'orders:stats'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert not utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_member_has_access_to_module_staff():
user = get_user(is_staff=True)
module_path = 'inventory'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_member_has_access_to_module_superuser():
user = get_user(is_superuser=True)
module_path = 'inventory'
module_paths_text = 'orders:order|mobile:dispatch,stats'
assert utils.member_has_access_to_module(
user,
module_path,
module_paths_text=module_paths_text)
def test_usertypes_required_access():
usertypes = 'planning_user,sales_user'
user = get_user(is_planning_user=True)
assert utils.usertypes_required(user, usertypes)
def test_usertypes_required_no_access():
usertypes = 'planning_user'
user = get_user(is_sales_user=True)
assert not utils.usertypes_required(user, usertypes)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment