diff options
author | Étienne Loks <etienne.loks@proxience.com> | 2015-12-08 02:26:03 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@proxience.com> | 2015-12-08 02:26:03 +0100 |
commit | 0643970751d46b73a7d1c48a6ef6593e7d43c8bc (patch) | |
tree | 5ea46df7c455810a61d3e278a80d6259c645a286 | |
parent | 74711e058edeb66d0e3cfb9f8277cab0accf2519 (diff) | |
download | Ishtar-0643970751d46b73a7d1c48a6ef6593e7d43c8bc.tar.bz2 Ishtar-0643970751d46b73a7d1c48a6ef6593e7d43c8bc.zip |
Use cache for faster rights checking
-rw-r--r-- | archaeological_files/models.py | 2 | ||||
-rw-r--r-- | archaeological_files/views.py | 3 | ||||
-rw-r--r-- | archaeological_operations/views.py | 26 | ||||
-rw-r--r-- | archaeological_warehouse/views.py | 12 | ||||
-rw-r--r-- | example_project/settings.py | 1 | ||||
-rw-r--r-- | ishtar_common/backend.py | 18 | ||||
-rw-r--r-- | ishtar_common/context_processors.py | 3 | ||||
-rw-r--r-- | ishtar_common/menu_base.py | 34 | ||||
-rw-r--r-- | ishtar_common/menus.py | 17 | ||||
-rw-r--r-- | ishtar_common/models.py | 48 | ||||
-rw-r--r-- | ishtar_common/views.py | 30 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 4 |
12 files changed, 123 insertions, 75 deletions
diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 93cbdff13..16cd6df65 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -46,7 +46,7 @@ class FileType(GeneralType): def is_preventive(cls, file_type_id, key=''): key = key or 'preventive' try: - preventive = FileType.objects.get(txt_idx=key).pk + preventive = FileType.get_cache(key).pk return file_type_id == preventive except FileType.DoesNotExist: return False diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 3f7e0bc8b..ad6eff854 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -50,7 +50,8 @@ RE_YEAR_INDEX = re.compile(r"([1-2][0-9]{3})-([0-9]+)") # eg.: 2014-123 def autocomplete_file(request): if not request.user.has_perm('ishtar_common.view_file', models.File) and \ not request.user.has_perm('ishtar_common.view_own_file', models.File) \ - and not request.user.ishtaruser.has_right('file_search'): + and not request.user.ishtaruser.has_right('file_search', + session=request.session): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 7ae6063bc..3af75da23 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -40,7 +40,8 @@ def autocomplete_patriarche(request, non_closed=True): models.Operation) and not request.user.has_perm('ishtar_common.view_own_operation', models.Operation) - and not request.user.ishtaruser.has_right('operation_search')): + and not request.user.ishtaruser.has_right( + 'operation_search', session=request.session)): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') @@ -90,9 +91,10 @@ def autocomplete_operation(request, non_closed=True): # person_types = request.user.ishtaruser.person.person_type if (not request.user.has_perm('ishtar_common.view_operation', models.Operation) - and not request.user.has_perm('ishtar_common.view_own_operation', - models.Operation) - and not request.user.ishtaruser.has_right('operation_search')): + and not request.user.has_perm( + 'ishtar_common.view_own_operation', models.Operation) + and not request.user.ishtaruser.has_right( + 'operation_search', session=request.session)): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') @@ -116,10 +118,10 @@ def autocomplete_operation(request, non_closed=True): def get_available_operation_code(request, year=None): - if not request.user.has_perm('ishtar_common.view_operation', - models.Operation)\ - and not request.user.has_perm('ishtar_common.view_own_operation', - models.Operation): + if not request.user.has_perm( + 'ishtar_common.view_operation', models.Operation)\ + and not request.user.has_perm( + 'ishtar_common.view_own_operation', models.Operation): return HttpResponse(mimetype='text/plain') data = json.dumps({'id': models.Operation.get_available_operation_code(year)}) @@ -365,10 +367,10 @@ administrativact_register_wizard = SearchWizard.as_view([ def generatedoc_administrativeactop(request, pk, template_pk=None): - if (not request.user.has_perm('ishtar_common.view_operation', - models.Operation) - and not request.user.has_perm('ishtar_common.view_own_operation', - models.Operation)): + if (not request.user.has_perm( + 'ishtar_common.view_operation', models.Operation) + and not request.user.has_perm( + 'ishtar_common.view_own_operation', models.Operation)): return HttpResponse(mimetype='text/plain') try: act_file = models.AdministrativeAct.objects.get(pk=pk) diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 10a7b9bf4..22eed80e3 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -41,11 +41,12 @@ get_container = get_item(models.Container, new_warehouse = new_item(models.Warehouse, WarehouseForm) new_container = new_item(models.Container, ContainerForm) + def autocomplete_warehouse(request): if not request.user.has_perm('ishtar_common.view_warehouse', models.Warehouse)\ - and not request.user.has_perm('ishtar_common.view_own_warehouse', - models.Warehouse) : + and not request.user.has_perm( + 'ishtar_common.view_own_warehouse', models.Warehouse): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') @@ -61,11 +62,12 @@ def autocomplete_warehouse(request): for warehouse in warehouses]) return HttpResponse(data, mimetype='text/plain') + def autocomplete_container(request): if not request.user.has_perm('ishtar_common.view_warehouse', - models.Warehouse)\ - and not request.user.has_perm('ishtar_common.view_own_warehouse', - models.Warehouse): + models.Warehouse)\ + and not request.user.has_perm( + 'ishtar_common.view_own_warehouse', models.Warehouse): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') diff --git a/example_project/settings.py b/example_project/settings.py index 43917523b..6a0bf4079 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -106,7 +106,6 @@ TEMPLATE_DIRS = ( ) AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', 'ishtar_common.backend.ObjectPermBackend', ) diff --git a/ishtar_common/backend.py b/ishtar_common/backend.py index 7ebdab221..0febd61b2 100644 --- a/ishtar_common/backend.py +++ b/ishtar_common/backend.py @@ -21,22 +21,18 @@ Permission backend to manage "own" objects """ -from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth.backends import ModelBackend from django.core.exceptions import ObjectDoesNotExist from django.db.models.loading import cache import models -class ObjectPermBackend(object): + +class ObjectPermBackend(ModelBackend): supports_object_permissions = True supports_anonymous_user = True - def authenticate(self, username, password): - # managed by the default backend - return None - - def has_perm(self, user_obj, perm, model=None, obj=None): + def has_perm(self, user_obj, perm, model=None, obj=None, session=None): if not user_obj.is_authenticated(): return False if not model: @@ -50,10 +46,10 @@ class ObjectPermBackend(object): is_ownperm = perm.split('.')[-1].split('_')[1] == 'own' except IndexError: is_ownperm = False - if ishtar_user.has_right('administrator'): + if ishtar_user.has_right('administrator', session=session): return True - main_right = ishtar_user.person.has_right(perm) \ - or user_obj.has_perm(perm) + main_right = ishtar_user.person.has_right(perm, session=session) \ + or user_obj.has_perm(perm) if not main_right or not is_ownperm: return main_right if obj is None: diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index 20b7f119a..ce303c344 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -58,7 +58,8 @@ def get_base_context(request): if 'CURRENT_ACTION' in request.session: dct['CURRENT_ACTION'] = request.session['CURRENT_ACTION'] current_action = dct['CURRENT_ACTION'] - menu = Menu(request.user, current_action=current_action) + menu = Menu(request.user, current_action=current_action, + session=request.session) menu.init() if menu.selected_idx is not None: dct['current_theme'] = "theme-%d" % (menu.selected_idx + 1) diff --git a/ishtar_common/menu_base.py b/ishtar_common/menu_base.py index 2331ecbd7..ab0a43d41 100644 --- a/ishtar_common/menu_base.py +++ b/ishtar_common/menu_base.py @@ -17,6 +17,7 @@ # See the file COPYING for details. + class SectionItem: def __init__(self, idx, label, childs=[]): self.idx = idx @@ -25,27 +26,29 @@ class SectionItem: self.available = False self.items = {} - def can_be_available(self, user): + def can_be_available(self, user, session=None): for child in self.childs: - if child.can_be_available(user): + if child.can_be_available(user, session=session): return True return False - def is_available(self, user, obj=None): + def is_available(self, user, obj=None, session=None): for child in self.childs: - if child.is_available(user, obj): + if child.is_available(user, obj, session=session): return True return False - def set_items(self, user, items, current_action=None): + def set_items(self, user, items, current_action=None, session=None): selected = None if user: - self.available = self.can_be_available(user) + self.available = self.can_be_available(user, session=session) for child in self.childs: - selected = child.set_items(user, items, current_action) or selected + selected = child.set_items(user, items, current_action, + session=session) or selected items[child.idx] = child return selected + class MenuItem: def __init__(self, idx, label, model=None, access_controls=[]): self.idx = idx @@ -54,22 +57,24 @@ class MenuItem: self.access_controls = access_controls self.available = False - def can_be_available(self, user): + def can_be_available(self, user, session=None): if not self.access_controls: return True prefix = (self.model._meta.app_label + '.') if self.model else '' for access_control in self.access_controls: access_control = prefix + access_control - if user.has_perm(access_control, self.model) or \ + if hasattr(user, 'ishtaruser') and \ + user.ishtaruser.has_perm(access_control, self.model, + session=session) or \ access_control in user.get_group_permissions(): return True # manage by person type if hasattr(user, 'ishtaruser'): - if user.ishtaruser.has_right(self.idx): + if user.ishtaruser.has_right(self.idx, session=session): return True return False - def is_available(self, user, obj=None): + def is_available(self, user, obj=None, session=None): if not self.access_controls: return True prefix = (self.model._meta.app_label + '.') if self.model else '' @@ -79,13 +84,12 @@ class MenuItem: return True # manage by person type if hasattr(user, 'ishtaruser'): - if ishtar_user.has_right(self.idx): + if user.ishtaruser.has_right(self.idx, session=session): return True return False - def set_items(self, user, items, current_action=None): + def set_items(self, user, items, current_action=None, session=None): if user: - self.available = self.can_be_available(user) + self.available = self.can_be_available(user, session=session) if self.idx == current_action: return True - diff --git a/ishtar_common/menus.py b/ishtar_common/menus.py index 6333a4197..e55b288bf 100644 --- a/ishtar_common/menus.py +++ b/ishtar_common/menus.py @@ -22,10 +22,7 @@ Menus """ from django.conf import settings -from django.utils.translation import ugettext_lazy as _ -from menu_base import SectionItem, MenuItem -import models _extra_menus = [] # collect menu from INSTALLED_APPS @@ -36,8 +33,8 @@ for app in settings.INSTALLED_APPS: _extra_menus += menu.MENU_SECTIONS # sort -__section_items = [menu for order, menu in sorted(_extra_menus, - key=lambda x:x[0])] +__section_items = [mnu for order, mnu in sorted(_extra_menus, + key=lambda x:x[0])] # regroup menus _section_items, __keys = [], [] for section_item in __section_items: @@ -51,22 +48,26 @@ for section_item in __section_items: if child.idx not in childs_idx: section_childs.append(child) + class Menu: childs = _section_items - def __init__(self, user, current_action=None): + + def __init__(self, user, current_action=None, session=None): self.user = user self.initialized = False self.items = {} self.current_action = current_action self.selected_idx = None + self.session = session def init(self): if self.initialized: return self.items = {} for idx, main_menu in enumerate(self.childs): - selected = main_menu.set_items(self.user, self.items, - self.current_action) + selected = main_menu.set_items( + self.user, self.items, + self.current_action, session=self.session) if selected: self.selected_idx = idx self.initialized = True diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 72b41e0cf..b5e371b25 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -434,6 +434,18 @@ class GeneralType(models.Model): for item in cls.objects.all(): item.generate_key() + @classmethod + def get_cache(cls, slug): + cache_key, value = get_cache(cls, slug) + if value: + return value + try: + obj = cls.objects.get(txt_idx=slug) + cache.set(cache_key, obj, settings.CACHE_TIMEOUT) + return obj + except cls.DoesNotExist: + return None + class ItemKey(models.Model): key = models.CharField(_(u"Key"), max_length=100) @@ -1938,19 +1950,29 @@ class Person(Address, Merge, OwnPerms, ValueGetter): def is_natural(self): return not self.attached_to - def has_right(self, right_name): + def has_right(self, right_name, session=None): if '.' in right_name: right_name = right_name.split('.')[-1] + res, cache_key = "", "" + if session: + cache_key = 'session-{}-{}'.format(session.session_key, right_name) + res = cache.get(cache_key) + if res in (True, False): + return res if type(right_name) in (list, tuple): - return bool(self.person_types.filter( + res = bool(self.person_types.filter( txt_idx__in=right_name).count()) or \ bool(self.person_types.filter( groups__permissions__codename__in=right_name).count()) # or self.person_types.filter(wizard__url_name__in=right_name).count()) - return bool(self.person_types.filter(txt_idx=right_name).count()) or \ - bool(self.person_types.filter( - groups__permissions__codename=right_name).count()) + else: + res = bool(self.person_types.filter(txt_idx=right_name).count()) or \ + bool(self.person_types.filter( + groups__permissions__codename=right_name).count()) # or self.person_types.filter(wizard__url_name=right_name).count()) + if session: + cache.set(cache_key, res, settings.CACHE_SMALLTIMEOUT) + return res def full_label(self): values = [] @@ -2010,12 +2032,24 @@ class IshtarUser(User): return IshtarUser.objects.create(user_ptr=user, username=default, person=person) - def has_right(self, right_name): - return self.person.has_right(right_name) + def has_right(self, right_name, session=None): + return self.person.has_right(right_name, session=session) def full_label(self): return self.person.full_label() + def has_perm(self, perm, model=None, session=None): + if not session: + return super(IshtarUser, self).has_perm(perm, model) + cache_key = 'usersession-{}-{}'.format(session.session_key, perm, + model or 'no') + res = cache.get(cache_key) + if res in (True, False): + return res + res = super(IshtarUser, self).has_perm(perm, model) + cache.set(cache_key, res, settings.CACHE_SMALLTIMEOUT) + return res + class AuthorType(GeneralType): class Meta: diff --git a/ishtar_common/views.py b/ishtar_common/views.py index ac29236ff..79e816bcb 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -167,21 +167,27 @@ def check_permission(request, action_slug, obj_id=None): # TODO return True if obj_id: - return menu.items[action_slug].is_available(request.user, obj_id) - return menu.items[action_slug].can_be_available(request.user) + return menu.items[action_slug].is_available(request.user, obj_id, + session=request.session) + return menu.items[action_slug].can_be_available(request.user, + session=request.session) -def autocomplete_person_permissive(request, person_types=None, attached_to=None, - is_ishtar_user=None): - return autocomplete_person(request, person_types=person_types, attached_to=attached_to, - is_ishtar_user=is_ishtar_user, permissive=True) +def autocomplete_person_permissive(request, person_types=None, + attached_to=None, is_ishtar_user=None): + return autocomplete_person( + request, person_types=person_types, attached_to=attached_to, + is_ishtar_user=is_ishtar_user, permissive=True) def autocomplete_person(request, person_types=None, attached_to=None, is_ishtar_user=None, permissive=False): - if not request.user.has_perm('ishtar_common.view_person', models.Person) and \ - not request.user.has_perm('ishtar_common.view_own_person', models.Person) \ - and not request.user.ishtaruser.has_right('person_search'): + if not request.user.has_perm('ishtar_common.view_person', + models.Person) and \ + not request.user.has_perm('ishtar_common.view_own_person', + models.Person) \ + and not request.user.ishtaruser.has_right('person_search', + session=request.session): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') @@ -325,7 +331,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[], continue if request.user.has_perm(model._meta.app_label + '.' + perm) \ or (request.user.is_authenticated() - and request.user.ishtaruser.has_right(perm)): + and request.user.ishtaruser.has_right( + perm, session=request.session)): allowed = True if "_own_" not in perm: own = False @@ -760,7 +767,8 @@ def autocomplete_organization(request, orga_type=None): models.Organization) and not request.user.has_perm('ishtar_common.view_own_organization', models.Organization) - and not request.user.ishtaruser.has_right('person_search')): + and not request.user.ishtaruser.has_right( + 'person_search', session=request.session)): return HttpResponse(mimetype='text/plain') if not request.GET.get('term'): return HttpResponse(mimetype='text/plain') diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 8fe1b5da2..45b46eb63 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -74,8 +74,8 @@ class Wizard(NamedUrlWizardView): # TODO: to be check if not hasattr(self.request.user, 'ishtaruser'): return False - return self.request.user.ishtaruser.has_right(('administrator', - step)) + return self.request.user.ishtaruser.has_right( + ('administrator', step), session=self.request.session) return check_right def __init__(self, *args, **kwargs): |