2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 03:56:43 +00:00
Matthias Mair faac6b6bf5
refactor: remove blank lines after docstring (#5736)
There shouldn't be any blank lines after the function docstring.
Remove the blank lines to fix this issue.

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2023-10-18 07:28:57 +11:00

200 lines
5.7 KiB
Python

"""Functions for triggering and responding to server side events."""
import logging
from django.conf import settings
from django.db import transaction
from django.db.models.signals import post_delete, post_save
from django.dispatch.dispatcher import receiver
from InvenTree.ready import canAppAccessDatabase, isImportingData
from InvenTree.tasks import offload_task
from plugin.registry import registry
logger = logging.getLogger('inventree')
def trigger_event(event, *args, **kwargs):
"""Trigger an event with optional arguments.
This event will be stored in the database,
and the worker will respond to it later on.
"""
from common.models import InvenTreeSetting
if not settings.PLUGINS_ENABLED:
# Do nothing if plugins are not enabled
return # pragma: no cover
if not InvenTreeSetting.get_setting('ENABLE_PLUGINS_EVENTS', False):
# Do nothing if plugin events are not enabled
return
# Make sure the database can be accessed and is not being tested rn
if not canAppAccessDatabase(allow_shell=True) and not settings.PLUGIN_TESTING_EVENTS:
logger.debug("Ignoring triggered event '%s' - database not ready", event)
return
logger.debug("Event triggered: '%s'", event)
# By default, force the event to be processed asynchronously
if 'force_async' not in kwargs and not settings.PLUGIN_TESTING_EVENTS:
kwargs['force_async'] = True
offload_task(
register_event,
event,
*args,
**kwargs
)
def register_event(event, *args, **kwargs):
"""Register the event with any interested plugins.
Note: This function is processed by the background worker,
as it performs multiple database access operations.
"""
from common.models import InvenTreeSetting
logger.debug("Registering triggered event: '%s'", event)
# Determine if there are any plugins which are interested in responding
if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting('ENABLE_PLUGINS_EVENTS'):
with transaction.atomic():
for slug, plugin in registry.plugins.items():
if not plugin.mixin_enabled('events'):
continue
# Only allow event registering for 'active' plugins
if not plugin.is_active():
continue
# Let the plugin decide if it wants to process this event
if not plugin.wants_process_event(event):
continue
logger.debug("Registering callback for plugin '%s'", slug)
# This task *must* be processed by the background worker,
# unless we are running CI tests
if 'force_async' not in kwargs and not settings.PLUGIN_TESTING_EVENTS:
kwargs['force_async'] = True
# Offload a separate task for each plugin
offload_task(
process_event,
slug,
event,
*args,
**kwargs
)
def process_event(plugin_slug, event, *args, **kwargs):
"""Respond to a triggered event.
This function is run by the background worker process.
This function may queue multiple functions to be handled by the background worker.
"""
plugin = registry.plugins.get(plugin_slug, None)
if plugin is None: # pragma: no cover
logger.error("Could not find matching plugin for '%s'", plugin_slug)
return
plugin.process_event(event, *args, **kwargs)
logger.debug("Plugin '%s' is processing triggered event '%s'", plugin_slug, event)
def allow_table_event(table_name):
"""Determine if an automatic event should be fired for a given table.
We *do not* want events to be fired for some tables!
"""
# Prevent table events during the data import process
if isImportingData():
return False # pragma: no cover
# Prevent table events when in testing mode (saves a lot of time)
if settings.TESTING:
return False
table_name = table_name.lower().strip()
# Ignore any tables which start with these prefixes
ignore_prefixes = [
'account_',
'auth_',
'authtoken_',
'django_',
'error_',
'exchange_',
'otp_',
'plugin_',
'socialaccount_',
'user_',
'users_',
]
if any(table_name.startswith(prefix) for prefix in ignore_prefixes):
return False
ignore_tables = [
'common_notificationentry',
'common_notificationmessage',
'common_webhookendpoint',
'common_webhookmessage',
'part_partpricing',
'part_partstocktake',
'part_partstocktakereport',
]
if table_name in ignore_tables:
return False
return True
@receiver(post_save)
def after_save(sender, instance, created, **kwargs):
"""Trigger an event whenever a database entry is saved."""
table = sender.objects.model._meta.db_table
instance_id = getattr(instance, 'id', None)
if instance_id is None:
return
if not allow_table_event(table):
return
if created:
trigger_event(
f'{table}.created',
id=instance.id,
model=sender.__name__,
)
else:
trigger_event(
f'{table}.saved',
id=instance.id,
model=sender.__name__,
)
@receiver(post_delete)
def after_delete(sender, instance, **kwargs):
"""Trigger an event whenever a database entry is deleted."""
table = sender.objects.model._meta.db_table
if not allow_table_event(table):
return
trigger_event(
f'{table}.deleted',
model=sender.__name__,
)