mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 13:05:42 +00:00
Part page loading improvements (#3185)
* Lazy load the pricing bom table when the "pricing" tab is selected * Update django-debug-toolbar configuration * Major refactoring for the 'can_build' function - Use a single annotated query to the db, rather than a for loop (which is what a caveman would use) - Query performance is greatly improved - Also refactors existing variant-part-stock subquery code, to make it re-usable * Use minified JS and CSS where possible * Render a 'preview' version of each part image - Saves load time when the image is quite large - Adds a data migration to render out the new variation * Adds 'preview' version of company images * Defer loading of javascript files Note: some cannot be deferred - jquery in particular * Crucial bugfix for user roles context - Previously was *not* being calculated correctly - A non-superuser role would most likely display pages incorrectly * Prevent loading of "about" on every page - Load dynamically when requested - Takes ~400ms! - Cuts out a lot of fat * Match displayed image size to preview image size * Utilize caching framework for accessing user "role" information - Reduces number of DB queries required by rendering framework * Remove redundant query elements * Remove 'stock' field from PartBrief serializer - A calculated field on a serializer is a *bad idea* when that calculation requires a DB hit * Query improvements for StockItem serializer - Remove calculated fields - Fix annotations * Bug fixes * Remove JS load test - Loading of JS files is now deferred, so the unit test does not work as it used to * Fix broken template for "maintenance" page * Remove thumbnail generation migrations - Already performed manually as part of ''invoke migrate" - Running as a migration causes unit test problems - Not sensible to run this as a data-migration anyway * tweak for build table
This commit is contained in:
@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from django.db.models import Q, UniqueConstraint
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
@ -474,13 +475,19 @@ def update_group_roles(group, debug=False):
|
||||
logger.info(f"Adding permission {child_perm} to group {group.name}")
|
||||
|
||||
|
||||
@receiver(post_save, sender=Group, dispatch_uid='create_missing_rule_sets')
|
||||
def create_missing_rule_sets(sender, instance, **kwargs):
|
||||
"""Called *after* a Group object is saved.
|
||||
def clear_user_role_cache(user):
|
||||
"""Remove user role permission information from the cache.
|
||||
|
||||
As the linked RuleSet instances are saved *before* the Group, then we can now use these RuleSet values to update the group permissions.
|
||||
- This function is called whenever the user / group is updated
|
||||
|
||||
Args:
|
||||
user: The User object to be expunged from the cache
|
||||
"""
|
||||
update_group_roles(instance)
|
||||
|
||||
for role in RuleSet.RULESET_MODELS.keys():
|
||||
for perm in ['add', 'change', 'view', 'delete']:
|
||||
key = f"role_{user}_{role}_{perm}"
|
||||
cache.delete(key)
|
||||
|
||||
|
||||
def check_user_role(user, role, permission):
|
||||
@ -491,6 +498,17 @@ def check_user_role(user, role, permission):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
# First, check the cache
|
||||
key = f"role_{user}_{role}_{permission}"
|
||||
|
||||
result = cache.get(key)
|
||||
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# Default for no match
|
||||
result = False
|
||||
|
||||
for group in user.groups.all():
|
||||
|
||||
for rule in group.rule_sets.all():
|
||||
@ -498,19 +516,24 @@ def check_user_role(user, role, permission):
|
||||
if rule.name == role:
|
||||
|
||||
if permission == 'add' and rule.can_add:
|
||||
return True
|
||||
result = True
|
||||
break
|
||||
|
||||
if permission == 'change' and rule.can_change:
|
||||
return True
|
||||
result = True
|
||||
break
|
||||
|
||||
if permission == 'view' and rule.can_view:
|
||||
return True
|
||||
result = True
|
||||
break
|
||||
|
||||
if permission == 'delete' and rule.can_delete:
|
||||
return True
|
||||
result = True
|
||||
break
|
||||
|
||||
# No matching permissions found
|
||||
return False
|
||||
# Save result to cache
|
||||
cache.set(key, result, timeout=3600)
|
||||
return result
|
||||
|
||||
|
||||
class Owner(models.Model):
|
||||
@ -659,3 +682,22 @@ def delete_owner(sender, instance, **kwargs):
|
||||
"""Callback function to delete an owner instance after either a new group or user instance is deleted."""
|
||||
owner = Owner.get_owner(instance)
|
||||
owner.delete()
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model(), dispatch_uid='clear_user_cache')
|
||||
def clear_user_cache(sender, instance, **kwargs):
|
||||
"""Callback function when a user object is saved"""
|
||||
|
||||
clear_user_role_cache(instance)
|
||||
|
||||
|
||||
@receiver(post_save, sender=Group, dispatch_uid='create_missing_rule_sets')
|
||||
def create_missing_rule_sets(sender, instance, **kwargs):
|
||||
"""Called *after* a Group object is saved.
|
||||
|
||||
As the linked RuleSet instances are saved *before* the Group, then we can now use these RuleSet values to update the group permissions.
|
||||
"""
|
||||
update_group_roles(instance)
|
||||
|
||||
for user in get_user_model().objects.filter(groups__name=instance.name):
|
||||
clear_user_role_cache(user)
|
||||
|
Reference in New Issue
Block a user