mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds sample plugin which responds to triggered events
- Adds some example trigger events for the "Part" model
This commit is contained in:
parent
a604d85f0f
commit
04d25a60b0
@ -60,6 +60,8 @@ import common.models
|
||||
|
||||
import part.settings as part_settings
|
||||
|
||||
from plugin.events import trigger_event
|
||||
|
||||
|
||||
logger = logging.getLogger("inventree")
|
||||
|
||||
@ -1980,10 +1982,10 @@ class Part(MPTTModel):
|
||||
|
||||
@property
|
||||
def attachment_count(self):
|
||||
""" Count the number of attachments for this part.
|
||||
"""
|
||||
Count the number of attachments for this part.
|
||||
If the part is a variant of a template part,
|
||||
include the number of attachments for the template part.
|
||||
|
||||
"""
|
||||
|
||||
return self.part_attachments.count()
|
||||
@ -2181,7 +2183,11 @@ def after_save_part(sender, instance: Part, created, **kwargs):
|
||||
Function to be executed after a Part is saved
|
||||
"""
|
||||
|
||||
if not created:
|
||||
trigger_event('part.saved', part_id=instance.pk)
|
||||
|
||||
if created:
|
||||
trigger_event('part.created', part_id=instance.pk)
|
||||
else:
|
||||
# Check part stock only if we are *updating* the part (not creating it)
|
||||
|
||||
# Run this check in the background
|
||||
|
@ -189,10 +189,10 @@ class EventMixin:
|
||||
which provide pairs of 'event':'function'
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Events are called by name, and based on the django signal nomenclature,
|
||||
e.g. 'part.pre_save'
|
||||
|
||||
|
||||
Receiving functions must be prototyped to match the 'event' they receive.
|
||||
|
||||
Example:
|
||||
|
@ -8,11 +8,14 @@ from __future__ import unicode_literals
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
|
||||
from common.models import InvenTreeSetting
|
||||
|
||||
from InvenTree.tasks import offload_task
|
||||
|
||||
from plugin.registry import plugin_registry
|
||||
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
@ -38,12 +41,30 @@ def trigger_event(event, *args, **kwargs):
|
||||
def process_event(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.
|
||||
"""
|
||||
|
||||
logger.info(f"Processing event '{event}'")
|
||||
|
||||
# Determine if there are any plugins which are interested in responding
|
||||
if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting('ENABLE_PLUGINS_EVENTS'):
|
||||
pass
|
||||
|
||||
# Run atomically, to ensure that either *all* tasks are registered, or *none*
|
||||
with transaction.atomic():
|
||||
for slug, callbacks in plugin_registry.mixins_events.items():
|
||||
# slug = plugin slug
|
||||
# callbacks = list of (event, function) tuples
|
||||
|
||||
for _event, _func in callbacks:
|
||||
if _event == event:
|
||||
|
||||
logger.info(f"Running task '{_func}' for plugin '{slug}'")
|
||||
|
||||
offload_task(
|
||||
_func,
|
||||
*args,
|
||||
**kwargs
|
||||
)
|
||||
|
@ -63,3 +63,15 @@ class InvenTreePlugin():
|
||||
raise error
|
||||
|
||||
return cfg
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Return True if this plugin is currently active
|
||||
"""
|
||||
|
||||
cfg = self.plugin_config()
|
||||
|
||||
if cfg:
|
||||
return cfg.active
|
||||
else:
|
||||
return False
|
||||
|
@ -56,8 +56,10 @@ class PluginsRegistry:
|
||||
|
||||
# integration specific
|
||||
self.installed_apps = [] # Holds all added plugin_paths
|
||||
|
||||
# mixins
|
||||
self.mixins_settings = {}
|
||||
self.mixins_events = {}
|
||||
|
||||
# region public plugin functions
|
||||
def load_plugins(self):
|
||||
@ -265,6 +267,7 @@ class PluginsRegistry:
|
||||
logger.info(f'Found {len(plugins)} active plugins')
|
||||
|
||||
self.activate_integration_settings(plugins)
|
||||
self.activate_integration_events(plugins)
|
||||
self.activate_integration_schedule(plugins)
|
||||
self.activate_integration_app(plugins, force_reload=force_reload)
|
||||
|
||||
@ -275,6 +278,7 @@ class PluginsRegistry:
|
||||
|
||||
self.deactivate_integration_app()
|
||||
self.deactivate_integration_schedule()
|
||||
self.deactivate_integration_events()
|
||||
self.deactivate_integration_settings()
|
||||
|
||||
def activate_integration_settings(self, plugins):
|
||||
@ -299,6 +303,41 @@ class PluginsRegistry:
|
||||
# clear cache
|
||||
self.mixins_settings = {}
|
||||
|
||||
def activate_integration_events(self, plugins):
|
||||
"""
|
||||
Activate triggered events mixin for applicable plugins
|
||||
"""
|
||||
|
||||
logger.info('Activating plugin events')
|
||||
|
||||
from common.models import InvenTreeSetting
|
||||
|
||||
self.mixins_events = {}
|
||||
|
||||
event_count = 0
|
||||
|
||||
if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting('ENABLE_PLUGINS_EVENTS'):
|
||||
|
||||
for slug, plugin in plugins:
|
||||
|
||||
if plugin.mixin_enabled('events'):
|
||||
config = plugin.plugin_config()
|
||||
|
||||
# Only activate events for plugins which are enabled
|
||||
if config and config.active:
|
||||
self.mixins_events[slug] = plugin.events
|
||||
|
||||
event_count += len(plugin.events)
|
||||
|
||||
if event_count > 0:
|
||||
logger.info(f"Registered callbacks for {event_count} events")
|
||||
|
||||
def deactivate_integration_events(self):
|
||||
"""
|
||||
Deactivate events for all plugins
|
||||
"""
|
||||
self.mixins_events = {}
|
||||
|
||||
def activate_integration_schedule(self, plugins):
|
||||
|
||||
logger.info('Activating plugin tasks')
|
||||
|
29
InvenTree/plugin/samples/integration/event_sample.py
Normal file
29
InvenTree/plugin/samples/integration/event_sample.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""
|
||||
Sample plugin which responds to events
|
||||
"""
|
||||
|
||||
from plugin import IntegrationPluginBase
|
||||
from plugin.mixins import EventMixin
|
||||
|
||||
|
||||
def on_part_saved(*args, **kwargs):
|
||||
"""
|
||||
Simple function which responds to a triggered event
|
||||
"""
|
||||
|
||||
part_id = kwargs['part_id']
|
||||
print(f"func on_part_saved() - part: {part_id}")
|
||||
|
||||
|
||||
class EventPlugin(EventMixin, IntegrationPluginBase):
|
||||
"""
|
||||
A sample plugin which provides supports for triggered events
|
||||
"""
|
||||
|
||||
PLUGIN_NAME = "EventPlugin"
|
||||
PLUGIN_SLUG = "event"
|
||||
PLUGIN_TITLE = "Triggered Events"
|
||||
|
||||
EVENTS = [
|
||||
('part.saved', 'plugin.samples.integration.event_sample.on_part_saved'),
|
||||
]
|
@ -32,7 +32,7 @@ class ScheduledTaskPlugin(ScheduleMixin, IntegrationPluginBase):
|
||||
'hello': {
|
||||
'func': 'plugin.samples.integration.scheduled_task.print_hello',
|
||||
'schedule': 'I',
|
||||
'minutes': 5,
|
||||
'minutes': 45,
|
||||
},
|
||||
'world': {
|
||||
'func': 'plugin.samples.integration.scheduled_task.print_hello',
|
||||
|
@ -90,7 +90,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><span class='fas fa-sitemap'></span></td>
|
||||
<td>{% trans "Installation path" %}</td>
|
||||
<td>{{ plugin.package_path }}</td>
|
||||
</tr>
|
||||
|
Loading…
Reference in New Issue
Block a user