From ba338bbb3fb1aaf185a102208f310f96ee41176e Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Wed, 10 Mar 2021 15:05:57 -0600 Subject: [PATCH] #5943 - Permits template tags to be used in the plugins namespace for certain filters --- netbox/utilities/tables.py | 13 ++--- .../templates/buttons/tr_changelog.html | 3 + .../templates/buttons/tr_delete.html | 3 + .../utilities/templates/buttons/tr_edit.html | 3 + netbox/utilities/templatetags/buttons.py | 57 +++++++++++++++++-- netbox/utilities/templatetags/helpers.py | 17 +++++- 6 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 netbox/utilities/templates/buttons/tr_changelog.html create mode 100644 netbox/utilities/templates/buttons/tr_delete.html create mode 100644 netbox/utilities/templates/buttons/tr_edit.html diff --git a/netbox/utilities/tables.py b/netbox/utilities/tables.py index 424cc6cd9..7532700c7 100644 --- a/netbox/utilities/tables.py +++ b/netbox/utilities/tables.py @@ -149,20 +149,15 @@ class ButtonsColumn(tables.TemplateColumn): attrs = {'td': {'class': 'text-right text-nowrap noprint'}} # Note that braces are escaped to allow for string formatting prior to template rendering template_code = """ + {{% load buttons %}} {{% if "changelog" in buttons %}} - - - + {{% tr_changelog_button record %}} {{% endif %}} {{% if "edit" in buttons and perms.{app_label}.change_{model_name} %}} - - - + {{% tr_edit_button record return_url_extra %}} {{% endif %}} {{% if "delete" in buttons and perms.{app_label}.delete_{model_name} %}} - - - + {{% tr_delete_button record return_url_extra %}} {{% endif %}} """ diff --git a/netbox/utilities/templates/buttons/tr_changelog.html b/netbox/utilities/templates/buttons/tr_changelog.html new file mode 100644 index 000000000..7a2b808b1 --- /dev/null +++ b/netbox/utilities/templates/buttons/tr_changelog.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/netbox/utilities/templates/buttons/tr_delete.html b/netbox/utilities/templates/buttons/tr_delete.html new file mode 100644 index 000000000..923eb911f --- /dev/null +++ b/netbox/utilities/templates/buttons/tr_delete.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/netbox/utilities/templates/buttons/tr_edit.html b/netbox/utilities/templates/buttons/tr_edit.html new file mode 100644 index 000000000..f60d7b407 --- /dev/null +++ b/netbox/utilities/templates/buttons/tr_edit.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/netbox/utilities/templatetags/buttons.py b/netbox/utilities/templatetags/buttons.py index c486dd2e5..d47a6f622 100644 --- a/netbox/utilities/templatetags/buttons.py +++ b/netbox/utilities/templatetags/buttons.py @@ -4,22 +4,71 @@ from django.urls import reverse from extras.models import ExportTemplate from utilities.utils import prepare_cloned_fields +from .helpers import _resolve_namespace + register = template.Library() +def _get_listviewname(instance): + app_label = _resolve_namespace(instance) + return f'{app_label}:{instance._meta.model_name}_list' + + def _get_viewname(instance, action): """ - Return the appropriate viewname for adding, editing, or deleting an instance. + Return the appropriate viewname for adding, editing, or deleting an instance or viewing. """ # Validate action assert action in ('add', 'edit', 'delete') - viewname = "{}:{}_{}".format( - instance._meta.app_label, instance._meta.model_name, action - ) + app_label = _resolve_namespace(instance) + viewname = f'{app_label}:{instance._meta.model_name}_{action}' return viewname +# +# Table buttons +# + +@register.inclusion_tag('buttons/tr_edit.html') +def tr_edit_button(instance, extra=None): + viewname = _get_viewname(instance, 'edit') + base_url = reverse(_get_listviewname(instance)) + url = reverse(viewname, kwargs={'pk': instance.pk}) + url = f'{url}?return_url={base_url}' + + if extra is not None: + url = f'{url}{extra}' + + return { + 'url': url, + } + +@register.inclusion_tag('buttons/tr_delete.html') +def tr_delete_button(instance, extra=None): + viewname = _get_viewname(instance, 'delete') + base_url = reverse(_get_listviewname(instance)) + url = reverse(viewname, kwargs={'pk': instance.pk}) + url = f'{url}?return_url={base_url}' + + if extra is not None: + url = f'{url}{extra}' + + return { + 'url': url, + } + +@register.inclusion_tag('buttons/tr_changelog.html') +def tr_changelog_button(instance): + app_label = _resolve_namespace(instance) + viewname = f'{app_label}:{instance._meta.model_name}_changelog' + url = reverse(viewname, kwargs={'pk': instance.pk}) + + return { + 'url': url, + } + + # # Instance buttons diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 01dce8479..cf85d4ac5 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -4,6 +4,7 @@ import re import yaml from django import template +from django.apps import apps from django.conf import settings from django.urls import NoReverseMatch, reverse from django.utils.html import strip_tags @@ -13,9 +14,21 @@ from markdown import markdown from utilities.forms import TableConfigForm from utilities.utils import foreground_color +from extras.plugins import PluginConfig + register = template.Library() +def _resolve_namespace(instance): + """ + Get the appropriate namespace for the app based on whether it is a Plugin or base application + """ + app = apps.get_app_config(instance._meta.app_label) + if isinstance(app, PluginConfig): + return f'plugins:{app.label}' + return f'{app.label}' + + # # Filters # @@ -80,7 +93,7 @@ def viewname(model, action): """ Return the view name for the given model and action. Does not perform any validation. """ - return f'{model._meta.app_label}:{model._meta.model_name}_{action}' + return f'{_resolve_namespace(model)}:{model._meta.model_name}_{action}' @register.filter() @@ -88,7 +101,7 @@ def validated_viewname(model, action): """ Return the view name for the given model and action if valid, or None if invalid. """ - viewname = f'{model._meta.app_label}:{model._meta.model_name}_{action}' + viewname = f'{_resolve_namespace(model)}:{model._meta.model_name}_{action}' try: # Validate and return the view name. We don't return the actual URL yet because many of the templates # are written to pass a name to {% url %}.