Просмотр исходного кода

add api urls and signals interface for detail route buttons

John Anderson 6 лет назад
Родитель
Сommit
71a8a13644

+ 0 - 0
netbox/extras/plugins/__init__.py


+ 34 - 0
netbox/extras/plugins/signals.py

@@ -0,0 +1,34 @@
+import django.dispatch
+from django.dispatch.dispatcher import NO_RECEIVERS
+
+
+class PluginSignal(django.dispatch.Signal):
+
+    def _sorted_receivers(self, sender):
+        orig_list = self._live_receivers(sender)
+        sorted_list = sorted(
+            orig_list,
+            key=lambda receiver: (
+                receiver.__module__,
+                receiver.__name__,
+            )
+        )
+        return sorted_list
+
+    def send(self, sender, **kwargs):
+        responses = []
+        if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
+            return responses
+
+        for receiver in self._sorted_receivers(sender):
+            response = receiver(signal=self, sender=sender, **kwargs)
+            responses.append((receiver, response))
+        return responses
+
+
+"""
+This signal collects templates which render buttons for object detail pages
+"""
+register_detail_page_buttons = PluginSignal(
+    providing_args=[]
+)

+ 0 - 0
netbox/extras/plugins/templatetags/__init__.py


+ 27 - 0
netbox/extras/templatetags/plugins.py

@@ -0,0 +1,27 @@
+from django import template as template_
+from django.template.loader import get_template
+from django.utils.safestring import mark_safe
+
+from extras.plugins.signals import register_detail_page_buttons
+
+
+register = template_.Library()
+
+
+@register.simple_tag()
+def plugin_buttons(obj):
+    """
+    Fire signal to collect all buttons registered by plugins
+    """
+    html = ''
+    responses = register_detail_page_buttons.send(obj)
+    for receiver, response in responses:
+        if not isinstance(response, list):
+            response = [response]
+        for template in response:
+            if isinstance(template, str):
+                template_text = get_template(template).render({'obj': obj})
+                html += template_text
+
+    return mark_safe(html)
+

+ 6 - 6
netbox/netbox/settings.py

@@ -261,7 +261,7 @@ INSTALLED_APPS = [
 ]
 ]
 
 
 # Middleware
 # Middleware
-MIDDLEWARE = (
+MIDDLEWARE = [
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'django_prometheus.middleware.PrometheusBeforeMiddleware',
     'django_prometheus.middleware.PrometheusBeforeMiddleware',
     'corsheaders.middleware.CorsMiddleware',
     'corsheaders.middleware.CorsMiddleware',
@@ -277,7 +277,7 @@ MIDDLEWARE = (
     'utilities.middleware.APIVersionMiddleware',
     'utilities.middleware.APIVersionMiddleware',
     'extras.middleware.ObjectChangeMiddleware',
     'extras.middleware.ObjectChangeMiddleware',
     'django_prometheus.middleware.PrometheusAfterMiddleware',
     'django_prometheus.middleware.PrometheusAfterMiddleware',
-)
+]
 
 
 ROOT_URLCONF = 'netbox.urls'
 ROOT_URLCONF = 'netbox.urls'
 
 
@@ -622,12 +622,12 @@ for entry_point in iter_entry_points(group='netbox.plugin', name=None):
 
 
     # Add middleware
     # Add middleware
     plugin_middleware = getattr(app_config_meta, 'middleware', [])
     plugin_middleware = getattr(app_config_meta, 'middleware', [])
-    if plugin_middleware:
+    if plugin_middleware and isinstance(plugin_middleware, list):
         MIDDLEWARE.extend(plugin_middleware)
         MIDDLEWARE.extend(plugin_middleware)
 
 
-    # Add middleware
+    # Add installed apps
     plugin_installed_apps = getattr(app_config_meta, 'installed_apps', [])
     plugin_installed_apps = getattr(app_config_meta, 'installed_apps', [])
-    if plugin_installed_apps:
+    if plugin_installed_apps and isinstance(plugin_installed_apps, list):
         INSTALLED_APPS.extend(plugin_installed_apps)
         INSTALLED_APPS.extend(plugin_installed_apps)
 
 
     # Verify required configuration settings
     # Verify required configuration settings
@@ -637,7 +637,7 @@ for entry_point in iter_entry_points(group='netbox.plugin', name=None):
         if setting not in PLUGINS_CONFIG[plugin]:
         if setting not in PLUGINS_CONFIG[plugin]:
             raise ImproperlyConfigured(
             raise ImproperlyConfigured(
                 "Plugin {} requires '{}' to be present in the PLUGINS_CONFIG section of configuration.py.".format(
                 "Plugin {} requires '{}' to be present in the PLUGINS_CONFIG section of configuration.py.".format(
-                    plugin, 
+                    plugin,
                     setting
                     setting
                 )
                 )
             )
             )

+ 16 - 3
netbox/netbox/urls.py

@@ -70,18 +70,31 @@ _patterns = [
 
 
 # Plugins
 # Plugins
 plugin_patterns = []
 plugin_patterns = []
+plugin_api_patterns = []
 for app in apps.get_app_configs():
 for app in apps.get_app_configs():
     if hasattr(app, 'NetBoxPluginMeta'):
     if hasattr(app, 'NetBoxPluginMeta'):
         if importlib.util.find_spec('{}.urls'.format(app.name)):
         if importlib.util.find_spec('{}.urls'.format(app.name)):
             urls = importlib.import_module('{}.urls'.format(app.name))
             urls = importlib.import_module('{}.urls'.format(app.name))
             url_slug = getattr(app.NetBoxPluginMeta, 'url_slug', app.label)
             url_slug = getattr(app.NetBoxPluginMeta, 'url_slug', app.label)
-            plugin_patterns.append(
-                path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))
-            )
+            if hasattr(urls, 'urlpatterns'):
+                plugin_patterns.append(
+                    path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))
+                )
+        if importlib.util.find_spec('{}.api'.format(app.name)):
+            if importlib.util.find_spec('{}.api.urls'.format(app.name)):
+                urls = importlib.import_module('{}.api.urls'.format(app.name))
+                if hasattr(urls, 'urlpatterns'):
+                    url_slug = getattr(app.NetBoxPluginMeta, 'url_slug', app.label)
+                    plugin_api_patterns.append(
+                        path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))
+                    )
 
 
 _patterns.append(
 _patterns.append(
     path('plugins/', include((plugin_patterns, 'plugins')))
     path('plugins/', include((plugin_patterns, 'plugins')))
 )
 )
+_patterns.append(
+    path('api/plugins/', include((plugin_api_patterns, 'plugins-api')))
+)
 
 
 if settings.DEBUG:
 if settings.DEBUG:
     import debug_toolbar
     import debug_toolbar

+ 2 - 0
netbox/templates/dcim/device.html

@@ -3,6 +3,7 @@
 {% load static %}
 {% load static %}
 {% load helpers %}
 {% load helpers %}
 {% load custom_links %}
 {% load custom_links %}
+{% load plugins %}
 
 
 {% block title %}{{ device }}{% endblock %}
 {% block title %}{{ device }}{% endblock %}
 
 
@@ -36,6 +37,7 @@
         </div>
         </div>
     </div>
     </div>
     <div class="pull-right noprint">
     <div class="pull-right noprint">
+        {% plugin_buttons device %}
         {% if show_graphs %}
         {% if show_graphs %}
             <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }}" data-url="{% url 'dcim-api:device-graphs' pk=device.pk %}" title="Show graphs">
             <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }}" data-url="{% url 'dcim-api:device-graphs' pk=device.pk %}" title="Show graphs">
                 <i class="fa fa-signal" aria-hidden="true"></i>
                 <i class="fa fa-signal" aria-hidden="true"></i>

+ 2 - 0
netbox/templates/dcim/site.html

@@ -2,6 +2,7 @@
 {% load buttons %}
 {% load buttons %}
 {% load custom_links %}
 {% load custom_links %}
 {% load helpers %}
 {% load helpers %}
+{% load plugins %}
 {% load static %}
 {% load static %}
 {% load tz %}
 {% load tz %}
 
 
@@ -33,6 +34,7 @@
         </div>
         </div>
     </div>
     </div>
     <div class="pull-right noprint">
     <div class="pull-right noprint">
+        {% plugin_buttons site %}
         {% if show_graphs %}
         {% if show_graphs %}
             <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ site.name }}" data-url="{% url 'dcim-api:site-graphs' pk=site.pk %}" title="Show graphs">
             <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ site.name }}" data-url="{% url 'dcim-api:site-graphs' pk=site.pk %}" title="Show graphs">
                 <i class="fa fa-signal" aria-hidden="true"></i>
                 <i class="fa fa-signal" aria-hidden="true"></i>