mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
added plugin template content injection to primary model detail views
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import collections
|
||||
import inspect
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.template.loader import get_template
|
||||
|
||||
from extras.utils import registry
|
||||
from .signals import register_detail_page_content_classes
|
||||
|
||||
|
||||
class PluginTemplateContent:
|
||||
"""
|
||||
This class is used to register plugin content to be injected into core NetBox templates.
|
||||
It contains methods that are overriden by plugin authors to return template content.
|
||||
|
||||
The `model` attribute on the class defines the which model detail page this class renders
|
||||
content for. It should be set as a string in the form '<app_label>.<model_name>'.
|
||||
"""
|
||||
model = None
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
|
||||
def render(self, template, extra_context=None):
|
||||
"""
|
||||
Convenience menthod for rendering the provided template name. The detail page object is automatically
|
||||
passed into the template context as `obj` but an additional context dictionary may be passed as `extra_context`.
|
||||
"""
|
||||
context = {'obj': self.obj}
|
||||
if isinstance(extra_context, dict):
|
||||
context.update(extra_context)
|
||||
|
||||
return get_template(template).render(context)
|
||||
|
||||
def left_page(self):
|
||||
"""
|
||||
Content that will be rendered on the left of the detail page view. Content should be returned as an
|
||||
HTML string. Note that content does not need to be marked as safe because this is automatically handled.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def right_page(self):
|
||||
"""
|
||||
Content that will be rendered on the right of the detail page view. Content should be returned as an
|
||||
HTML string. Note that content does not need to be marked as safe because this is automatically handled.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def full_width_page(self):
|
||||
"""
|
||||
Content that will be rendered within the full width of the detail page view. Content should be returned as an
|
||||
HTML string. Note that content does not need to be marked as safe because this is automatically handled.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def buttons(self):
|
||||
"""
|
||||
Buttons that will be rendered and added to the existing list of buttons on the detail page view. Content
|
||||
should be returned as an HTML string. Note that content does not need to be marked as safe because this is
|
||||
automatically handled.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def register_content_classes():
|
||||
registry.plugin_template_content_classes = collections.defaultdict(list)
|
||||
|
||||
responses = register_detail_page_content_classes.send('registration_event')
|
||||
for receiver, response in responses:
|
||||
if not isinstance(response, list):
|
||||
response = [response]
|
||||
for template_class in response:
|
||||
if not inspect.isclass(template_class):
|
||||
raise TypeError('Plugin content class {} was passes as an instance!'.format(template_class))
|
||||
if not issubclass(template_class, PluginTemplateContent):
|
||||
raise TypeError('{} is not a subclass of extras.plugins.PluginTemplateContent!'.format(template_class))
|
||||
if template_class.model is None:
|
||||
raise TypeError('Plugin content class {} does not define a valid model!'.format(template_class))
|
||||
|
||||
registry.plugin_template_content_classes[template_class.model].append(template_class)
|
||||
|
||||
|
||||
def get_content_classes(model):
|
||||
if not hasattr(registry, 'plugin_template_content_classes'):
|
||||
register_content_classes()
|
||||
|
||||
return registry.plugin_template_content_classes.get(model, [])
|
||||
|
@@ -27,8 +27,8 @@ class PluginSignal(django.dispatch.Signal):
|
||||
|
||||
|
||||
"""
|
||||
This signal collects templates which render buttons for object detail pages
|
||||
This signal collects templates which render content for object detail pages
|
||||
"""
|
||||
register_detail_page_buttons = PluginSignal(
|
||||
register_detail_page_content_classes = PluginSignal(
|
||||
providing_args=[]
|
||||
)
|
||||
|
@@ -2,26 +2,59 @@ 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
|
||||
from extras.plugins import get_content_classes
|
||||
|
||||
|
||||
register = template_.Library()
|
||||
|
||||
|
||||
def _get_registered_content(obj, method):
|
||||
"""
|
||||
Given an object and a PluginTemplateContent method name, return all the registered content for the
|
||||
object's model.
|
||||
"""
|
||||
html = ''
|
||||
|
||||
plugin_template_classes = get_content_classes(obj._meta.label_lower)
|
||||
for plugin_template_class in plugin_template_classes:
|
||||
plugin_template_renderer = plugin_template_class(obj)
|
||||
try:
|
||||
content = getattr(plugin_template_renderer, method)()
|
||||
except NotImplementedError:
|
||||
# This content renderer class does not define content for this method
|
||||
continue
|
||||
html += content
|
||||
|
||||
return mark_safe(html)
|
||||
|
||||
|
||||
@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 _get_registered_content(obj, 'buttons')
|
||||
|
||||
return mark_safe(html)
|
||||
|
||||
@register.simple_tag()
|
||||
def plugin_left_page(obj):
|
||||
"""
|
||||
Fire signal to collect all left page content registered by plugins
|
||||
"""
|
||||
return _get_registered_content(obj, 'left_page')
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def plugin_right_page(obj):
|
||||
"""
|
||||
Fire signal to collect all right page content registered by plugins
|
||||
"""
|
||||
return _get_registered_content(obj, 'right_page')
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def plugin_full_width_page(obj):
|
||||
"""
|
||||
Fire signal to collect all full width page content registered by plugins
|
||||
"""
|
||||
return _get_registered_content(obj, 'full_width_page')
|
||||
|
Reference in New Issue
Block a user