2
0
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:
Oliver
2022-06-17 21:26:28 +10:00
committed by GitHub
parent 0d01ea2f2e
commit 74bec86675
51 changed files with 3592 additions and 2212 deletions

View File

@ -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)