/ server_code / authorisation.py
authorisation.py
1 # SPDX-License-Identifier: MIT 2 # 3 # Copyright (c) 2021 The Anvil Extras project team members listed at 4 # https://github.com/anvilistas/anvil-extras/graphs/contributors 5 # 6 # This software is published at https://github.com/anvilistas/anvil-extras 7 import functools 8 from operator import itemgetter 9 10 import anvil.users 11 from anvil.tables import app_tables 12 13 __version__ = "3.1.0" 14 15 config = {"get_roles": itemgetter("roles")} 16 17 18 def set_config(**kwargs): 19 if "get_roles" in kwargs: 20 _set_user_roles_getter(kwargs["get_roles"]) 21 22 23 def _get_roles_from_table(table_name, user): 24 return getattr(app_tables, table_name).get(user=user)["roles"] 25 26 27 def _set_user_roles_getter(option): 28 if option is None: 29 config["get_roles"] = itemgetter("roles") 30 elif isinstance(option, str): # table name 31 config["get_roles"] = functools.partial(_get_roles_from_table, option) 32 else: 33 raise TypeError("get_roles: option is not valid.") 34 35 36 def authentication_required(func): 37 """A decorator to ensure only a valid user can call a server function""" 38 39 @functools.wraps(func) 40 def wrapper(*args, **kwargs): 41 if anvil.users.get_user() is None: 42 raise ValueError("Authentication required") 43 else: 44 return func(*args, **kwargs) 45 46 return wrapper 47 48 49 def has_permission(permissions): 50 """Returns True/False depending on whether a user has permission or not""" 51 user = anvil.users.get_user() 52 if user is None: 53 return False 54 55 if isinstance(permissions, str): 56 required_permissions = set([permissions]) 57 else: 58 required_permissions = set(permissions) 59 60 try: 61 user_permissions = set( 62 permission["name"] 63 for role in config["get_roles"](user) 64 for permission in role["permissions"] 65 ) 66 except TypeError: 67 return False 68 69 return required_permissions.issubset(user_permissions) 70 71 72 def check_permissions(permissions): 73 """Checks a users permissions, raises ValueError if user does not have permissions""" 74 if has_permission(permissions): 75 return 76 77 user = anvil.users.get_user() 78 fail = "Authentication" if user is None else "Authorisation" 79 80 raise ValueError(f"{fail} required") 81 82 83 def authorisation_required(permissions): 84 """A decorator to ensure a user has sufficient permissions to call a server function""" 85 86 def decorator(func): 87 @functools.wraps(func) 88 def wrapper(*args, **kwargs): 89 check_permissions(permissions) 90 return func(*args, **kwargs) 91 92 return wrapper 93 94 return decorator