mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-27 11:51:50 +01:00
* Move extras.plugins to netbox.plugins & add deprecation warnings * Move plugin template tags from extras to utilities * Move plugins tests from extras to netbox * Add TODO reminders for v4.0
This commit is contained in:
@@ -1,148 +1,9 @@
|
||||
import collections
|
||||
from importlib import import_module
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.module_loading import import_string
|
||||
from packaging import version
|
||||
|
||||
from netbox.registry import registry
|
||||
from netbox.search import register_search
|
||||
from .navigation import *
|
||||
from .registration import *
|
||||
from .templates import *
|
||||
from .utils import *
|
||||
|
||||
# Initialize plugin registry
|
||||
registry['plugins'].update({
|
||||
'graphql_schemas': [],
|
||||
'menus': [],
|
||||
'menu_items': {},
|
||||
'preferences': {},
|
||||
'template_extensions': collections.defaultdict(list),
|
||||
})
|
||||
|
||||
DEFAULT_RESOURCE_PATHS = {
|
||||
'search_indexes': 'search.indexes',
|
||||
'graphql_schema': 'graphql.schema',
|
||||
'menu': 'navigation.menu',
|
||||
'menu_items': 'navigation.menu_items',
|
||||
'template_extensions': 'template_content.template_extensions',
|
||||
'user_preferences': 'preferences.preferences',
|
||||
}
|
||||
from netbox.plugins import PluginConfig
|
||||
|
||||
|
||||
#
|
||||
# Plugin AppConfig class
|
||||
#
|
||||
|
||||
class PluginConfig(AppConfig):
|
||||
"""
|
||||
Subclass of Django's built-in AppConfig class, to be used for NetBox plugins.
|
||||
"""
|
||||
# Plugin metadata
|
||||
author = ''
|
||||
author_email = ''
|
||||
description = ''
|
||||
version = ''
|
||||
|
||||
# Root URL path under /plugins. If not set, the plugin's label will be used.
|
||||
base_url = None
|
||||
|
||||
# Minimum/maximum compatible versions of NetBox
|
||||
min_version = None
|
||||
max_version = None
|
||||
|
||||
# Default configuration parameters
|
||||
default_settings = {}
|
||||
|
||||
# Mandatory configuration parameters
|
||||
required_settings = []
|
||||
|
||||
# Middleware classes provided by the plugin
|
||||
middleware = []
|
||||
|
||||
# Django-rq queues dedicated to the plugin
|
||||
queues = []
|
||||
|
||||
# Django apps to append to INSTALLED_APPS when plugin requires them.
|
||||
django_apps = []
|
||||
|
||||
# Optional plugin resources
|
||||
search_indexes = None
|
||||
graphql_schema = None
|
||||
menu = None
|
||||
menu_items = None
|
||||
template_extensions = None
|
||||
user_preferences = None
|
||||
|
||||
def _load_resource(self, name):
|
||||
# Import from the configured path, if defined.
|
||||
if path := getattr(self, name, None):
|
||||
return import_string(f"{self.__module__}.{path}")
|
||||
|
||||
# Fall back to the resource's default path. Return None if the module has not been provided.
|
||||
default_path = f'{self.__module__}.{DEFAULT_RESOURCE_PATHS[name]}'
|
||||
default_module, resource_name = default_path.rsplit('.', 1)
|
||||
try:
|
||||
module = import_module(default_module)
|
||||
return getattr(module, resource_name, None)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
def ready(self):
|
||||
plugin_name = self.name.rsplit('.', 1)[-1]
|
||||
|
||||
# Register search extensions (if defined)
|
||||
search_indexes = self._load_resource('search_indexes') or []
|
||||
for idx in search_indexes:
|
||||
register_search(idx)
|
||||
|
||||
# Register template content (if defined)
|
||||
if template_extensions := self._load_resource('template_extensions'):
|
||||
register_template_extensions(template_extensions)
|
||||
|
||||
# Register navigation menu and/or menu items (if defined)
|
||||
if menu := self._load_resource('menu'):
|
||||
register_menu(menu)
|
||||
if menu_items := self._load_resource('menu_items'):
|
||||
register_menu_items(self.verbose_name, menu_items)
|
||||
|
||||
# Register GraphQL schema (if defined)
|
||||
if graphql_schema := self._load_resource('graphql_schema'):
|
||||
register_graphql_schema(graphql_schema)
|
||||
|
||||
# Register user preferences (if defined)
|
||||
if user_preferences := self._load_resource('user_preferences'):
|
||||
register_user_preferences(plugin_name, user_preferences)
|
||||
|
||||
@classmethod
|
||||
def validate(cls, user_config, netbox_version):
|
||||
|
||||
# Enforce version constraints
|
||||
current_version = version.parse(netbox_version)
|
||||
if cls.min_version is not None:
|
||||
min_version = version.parse(cls.min_version)
|
||||
if current_version < min_version:
|
||||
raise ImproperlyConfigured(
|
||||
f"Plugin {cls.__module__} requires NetBox minimum version {cls.min_version}."
|
||||
)
|
||||
if cls.max_version is not None:
|
||||
max_version = version.parse(cls.max_version)
|
||||
if current_version > max_version:
|
||||
raise ImproperlyConfigured(
|
||||
f"Plugin {cls.__module__} requires NetBox maximum version {cls.max_version}."
|
||||
)
|
||||
|
||||
# Verify required configuration settings
|
||||
for setting in cls.required_settings:
|
||||
if setting not in user_config:
|
||||
raise ImproperlyConfigured(
|
||||
f"Plugin {cls.__module__} requires '{setting}' to be present in the PLUGINS_CONFIG section of "
|
||||
f"configuration.py."
|
||||
)
|
||||
|
||||
# Apply default configuration values
|
||||
for setting, value in cls.default_settings.items():
|
||||
if setting not in user_config:
|
||||
user_config[setting] = value
|
||||
# TODO: Remove in v4.0
|
||||
warnings.warn(f"{__name__} is deprecated. Import from netbox.plugins instead.", DeprecationWarning)
|
||||
|
||||
Reference in New Issue
Block a user