2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 11:10:54 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into api-mixin

This commit is contained in:
Matthias
2022-01-08 21:50:37 +01:00
82 changed files with 10834 additions and 9705 deletions

View File

@ -1,68 +1,193 @@
"""default mixins for IntegrationMixins"""
"""
Plugin mixin classes
"""
import logging
import json
import requests
from django.conf.urls import url, include
from django.db.utils import OperationalError, ProgrammingError
from plugin.models import PluginConfig, PluginSetting
from plugin.urls import PLUGIN_BASE
class GlobalSettingsMixin:
"""Mixin that enables global settings for the plugin"""
logger = logging.getLogger('inventree')
class SettingsMixin:
"""
Mixin that enables global settings for the plugin
"""
class MixinMeta:
"""meta options for this mixin"""
MIXIN_NAME = 'Global settings'
MIXIN_NAME = 'Settings'
def __init__(self):
super().__init__()
self.add_mixin('globalsettings', 'has_globalsettings', __class__)
self.globalsettings = self.setup_globalsettings()
def setup_globalsettings(self):
"""
setup global settings for this plugin
"""
return getattr(self, 'GLOBALSETTINGS', None)
self.add_mixin('settings', 'has_settings', __class__)
self.settings = getattr(self, 'SETTINGS', {})
@property
def has_globalsettings(self):
def has_settings(self):
"""
does this plugin use custom global settings
Does this plugin use custom global settings
"""
return bool(self.globalsettings)
return bool(self.settings)
def get_setting(self, key):
"""
Return the 'value' of the setting associated with this plugin
"""
return PluginSetting.get_setting(key, plugin=self)
def set_setting(self, key, value, user=None):
"""
Set plugin setting value by key
"""
try:
plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name())
except (OperationalError, ProgrammingError):
plugin = None
if not plugin:
# Cannot find associated plugin model, return
return
PluginSetting.set_setting(key, value, user, plugin=plugin)
class ScheduleMixin:
"""
Mixin that provides support for scheduled tasks.
Implementing classes must provide a dict object called SCHEDULED_TASKS,
which provides information on the tasks to be scheduled.
SCHEDULED_TASKS = {
# Name of the task (will be prepended with the plugin name)
'test_server': {
'func': 'myplugin.tasks.test_server', # Python function to call (no arguments!)
'schedule': "I", # Schedule type (see django_q.Schedule)
'minutes': 30, # Number of minutes (only if schedule type = Minutes)
'repeats': 5, # Number of repeats (leave blank for 'forever')
}
}
Note: 'schedule' parameter must be one of ['I', 'H', 'D', 'W', 'M', 'Q', 'Y']
"""
ALLOWABLE_SCHEDULE_TYPES = ['I', 'H', 'D', 'W', 'M', 'Q', 'Y']
SCHEDULED_TASKS = {}
class MixinMeta:
MIXIN_NAME = 'Schedule'
def __init__(self):
super().__init__()
self.add_mixin('schedule', 'has_scheduled_tasks', __class__)
self.scheduled_tasks = getattr(self, 'SCHEDULED_TASKS', {})
self.validate_scheduled_tasks()
@property
def globalsettingspatterns(self):
"""
get patterns for InvenTreeSetting defintion
"""
if self.has_globalsettings:
return {f'PLUGIN_{self.slug.upper()}_{key}': value for key, value in self.globalsettings.items()}
return None
def has_scheduled_tasks(self):
return bool(self.scheduled_tasks)
def _globalsetting_name(self, key):
"""get global name of setting"""
return f'PLUGIN_{self.slug.upper()}_{key}'
def validate_scheduled_tasks(self):
"""
Check that the provided scheduled tasks are valid
"""
def get_globalsetting(self, key):
"""
get plugin global setting by key
"""
from common.models import InvenTreeSetting
return InvenTreeSetting.get_setting(self._globalsetting_name(key))
if not self.has_scheduled_tasks:
raise ValueError("SCHEDULED_TASKS not defined")
def set_globalsetting(self, key, value, user):
for key, task in self.scheduled_tasks.items():
if 'func' not in task:
raise ValueError(f"Task '{key}' is missing 'func' parameter")
if 'schedule' not in task:
raise ValueError(f"Task '{key}' is missing 'schedule' parameter")
schedule = task['schedule'].upper().strip()
if schedule not in self.ALLOWABLE_SCHEDULE_TYPES:
raise ValueError(f"Task '{key}': Schedule '{schedule}' is not a valid option")
# If 'minutes' is selected, it must be provided!
if schedule == 'I' and 'minutes' not in task:
raise ValueError(f"Task '{key}' is missing 'minutes' parameter")
def get_task_name(self, key):
# Generate a 'unique' task name
slug = self.plugin_slug()
return f"plugin.{slug}.{key}"
def get_task_names(self):
# Returns a list of all task names associated with this plugin instance
return [self.get_task_name(key) for key in self.scheduled_tasks.keys()]
def register_tasks(self):
"""
set plugin global setting by key
Register the tasks with the database
"""
from common.models import InvenTreeSetting
return InvenTreeSetting.set_setting(self._globalsetting_name(key), value, user)
try:
from django_q.models import Schedule
for key, task in self.scheduled_tasks.items():
task_name = self.get_task_name(key)
# If a matching scheduled task does not exist, create it!
if not Schedule.objects.filter(name=task_name).exists():
logger.info(f"Adding scheduled task '{task_name}'")
Schedule.objects.create(
name=task_name,
func=task['func'],
schedule_type=task['schedule'],
minutes=task.get('minutes', None),
repeats=task.get('repeats', -1),
)
except (ProgrammingError, OperationalError):
# Database might not yet be ready
logger.warning("register_tasks failed, database not ready")
def unregister_tasks(self):
"""
Deregister the tasks with the database
"""
try:
from django_q.models import Schedule
for key, task in self.scheduled_tasks.items():
task_name = self.get_task_name(key)
try:
scheduled_task = Schedule.objects.get(name=task_name)
scheduled_task.delete()
except Schedule.DoesNotExist:
pass
except (ProgrammingError, OperationalError):
# Database might not yet be ready
logger.warning("unregister_tasks failed, database not ready")
class UrlsMixin:
"""Mixin that enables urls for the plugin"""
"""
Mixin that enables custom URLs for the plugin
"""
class MixinMeta:
"""meta options for this mixin"""
MIXIN_NAME = 'URLs'
def __init__(self):
@ -108,12 +233,17 @@ class UrlsMixin:
class NavigationMixin:
"""Mixin that enables adding navigation links with the plugin"""
"""
Mixin that enables custom navigation links with the plugin
"""
NAVIGATION_TAB_NAME = None
NAVIGATION_TAB_ICON = "fas fa-question"
class MixinMeta:
"""meta options for this mixin"""
"""
meta options for this mixin
"""
MIXIN_NAME = 'Navigation Links'
def __init__(self):
@ -155,7 +285,10 @@ class NavigationMixin:
class AppMixin:
"""Mixin that enables full django app functions for a plugin"""
"""
Mixin that enables full django app functions for a plugin
"""
class MixinMeta:
"""meta options for this mixin"""
MIXIN_NAME = 'App registration'