From 2674e0e6a8db2252e9284c9e28bff200826315a8 Mon Sep 17 00:00:00 2001 From: Renato Almeida de Oliveira Zaroubin Date: Tue, 1 Apr 2025 00:04:16 +0000 Subject: [PATCH] Move ObjectContactsView back to tenancy.views and using ObjectChildrenView --- netbox/netbox/models/features.py | 2 +- netbox/netbox/views/generic/feature_views.py | 76 ------------------- netbox/templates/tenancy/object_contacts.html | 58 +------------- netbox/tenancy/views.py | 37 ++++++++- 4 files changed, 40 insertions(+), 133 deletions(-) diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index cf8f1afe8..85edb9b5f 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -661,7 +661,7 @@ def register_models(*models): # Register applicable feature views for the model if issubclass(model, ContactsMixin): register_model_view(model, 'contacts', kwargs={'model': model})( - 'netbox.views.generic.ObjectContactsView' + 'tenancy.views.ObjectContactsView' ) if issubclass(model, JournalingMixin): register_model_view(model, 'journal', kwargs={'model': model})( diff --git a/netbox/netbox/views/generic/feature_views.py b/netbox/netbox/views/generic/feature_views.py index bab249f58..1e17d5354 100644 --- a/netbox/netbox/views/generic/feature_views.py +++ b/netbox/netbox/views/generic/feature_views.py @@ -12,19 +12,12 @@ from core.tables import JobTable, ObjectChangeTable from extras.forms import JournalEntryForm from extras.models import JournalEntry from extras.tables import JournalEntryTable -from tenancy.models import ContactAssignment -from tenancy.tables import ContactAssignmentTable -from tenancy.filtersets import ContactAssignmentFilterSet -from tenancy.forms import ContactAssignmentFilterForm from utilities.permissions import get_permission_for_model from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab -from utilities.htmx import htmx_partial from .base import BaseMultiObjectView -from .mixins import ActionsMixin, TableMixin __all__ = ( 'BulkSyncDataView', - 'ObjectContactsView', 'ObjectChangeLogView', 'ObjectJobsView', 'ObjectJournalView', @@ -32,75 +25,6 @@ __all__ = ( ) -class ObjectContactsView(ConditionalLoginRequiredMixin, ActionsMixin, TableMixin, View): - """ - Show all Contacts associated with an object. The model class must be passed as a keyword argument when referencing - this view in a URL path. For example: - path('sites//contacts/', ObjectContactsView.as_view(), name='site_contacts', kwargs={'model': Site}), - Attributes: - base_template: The name of the template to extend. If not provided, "{app}/{model}.html" will be used. - """ - base_template = None - tab = ViewTab( - label=_('Contacts'), - badge=lambda obj: obj.contacts.count(), - permission='tenancy.view_contactassignment', - weight=9000 - ) - table = ContactAssignmentTable - filterset = ContactAssignmentFilterSet - filterset_form = ContactAssignmentFilterForm - - def get(self, request, model, **kwargs): - # Handle QuerySet restriction of parent object if needed - if hasattr(model.objects, 'restrict'): - obj = get_object_or_404(model.objects.restrict(request.user, 'view'), **kwargs) - else: - obj = get_object_or_404(model, **kwargs) - - # Gather all Contact Assignments for this object - content_type = ContentType.objects.get_for_model(model) - contactassignments = ContactAssignment.objects.restrict(request.user, 'view').prefetch_related( - 'contact', - ).filter( - object_type=content_type, - object_id=obj.pk - ).order_by('priority', 'contact', 'role') - contactassignments = self.filterset(request.GET, contactassignments, request=request).qs - - # Determine the available actions - actions = self.get_permitted_actions(request.user, model=ContactAssignment) - has_bulk_actions = any([a.startswith('bulk_') for a in actions]) - - table = self.get_table(contactassignments, request, has_bulk_actions) - table.columns.hide('object_type') - table.columns.hide('object') - - if htmx_partial(request): - return render(request, 'htmx/table.html', { - 'object': obj, - 'table': table, - 'model': ContactAssignment, - }) - - # Default to using "/.html" as the template, if it exists. Otherwise, - # fall back to using base.html. - if self.base_template is None: - self.base_template = f"{model._meta.app_label}/{model._meta.model_name}.html" - - return render(request, 'tenancy/object_contacts.html', { - 'object': obj, - 'model': ContactAssignment, - 'base_template': self.base_template, - 'table': table, - 'table_config': f'{table.name}_config', - 'filter_form': self.filterset_form(request.GET) if self.filterset_form else None, - 'actions': actions, - 'tab': self.tab, - 'return_url': request.get_full_path(), - }) - - class ObjectChangeLogView(ConditionalLoginRequiredMixin, View): """ Present a history of changes made to a particular object. The model class must be passed as a keyword argument diff --git a/netbox/templates/tenancy/object_contacts.html b/netbox/templates/tenancy/object_contacts.html index 8a03caff5..dc5efbd0d 100644 --- a/netbox/templates/tenancy/object_contacts.html +++ b/netbox/templates/tenancy/object_contacts.html @@ -1,4 +1,5 @@ -{% extends base_template %}{% load helpers %} +{% extends 'generic/object_children.html' %} +{% load helpers %} {% load i18n %} {% block extra_controls %} @@ -9,57 +10,4 @@ {% endwith %} {% endif %} -{% endblock %} - -{% block content %} - {% block table_controls %} - {% include 'inc/table_controls_htmx.html' with table_modal=table_config %} - {% endblock table_controls %} -
- {% csrf_token %} -
-
- {% include 'htmx/table.html' %} -
-
-
- {% block bulk_controls %} -
- {# Bulk edit buttons #} - {% block bulk_edit_controls %} - {% with bulk_edit_view=model|validated_viewname:"bulk_edit" %} - {% if 'bulk_edit' in actions and bulk_edit_view %} - - {% endif %} - {% endwith %} - {% endblock bulk_edit_controls %} -
-
- {# Bulk delete buttons #} - {% block bulk_delete_controls %} - {% with bulk_delete_view=model|validated_viewname:"bulk_delete" %} - {% if 'bulk_delete' in actions and bulk_delete_view %} - - {% endif %} - {% endwith %} - {% endblock bulk_delete_controls %} -
- {# Other bulk action buttons #} - {% block bulk_extra_controls %}{% endblock %} - {% endblock bulk_controls %} -
-
-{% endblock content %} - -{% block modals %} - {{ block.super }} - {% table_config_form table %} -{% endblock modals %} \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index dd584d745..f17fec2ea 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -1,13 +1,48 @@ from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404 +from django.utils.translation import gettext_lazy as _ from netbox.views import generic from utilities.query import count_related -from utilities.views import GetRelatedModelsMixin, register_model_view +from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view from . import filtersets, forms, tables from .models import * +class ObjectContactsView(generic.ObjectChildrenView): + child_model = ContactAssignment + table = tables.ContactAssignmentTable + filterset = filtersets.ContactAssignmentFilterSet + filterset_form = forms.ContactAssignmentFilterForm + template_name = 'tenancy/object_contacts.html' + tab = ViewTab( + label=_('Contacts'), + badge=lambda obj: obj.contacts.count(), + permission='tenancy.view_contactassignment', + weight=5000 + ) + + def dispatch(self, request, *args, **kwargs): + model = kwargs.pop('model') + self.queryset = model.objects.all() + return super().dispatch(request, *args, **kwargs) + + def get_children(self, request, parent): + return ContactAssignment.objects.restrict(request.user, 'view').filter( + object_type=ContentType.objects.get_for_model(parent), + object_id=parent.pk + ).order_by('priority', 'contact', 'role') + + def get_table(self, *args, **kwargs): + table = super().get_table(*args, **kwargs) + + # Hide object columns + table.columns.hide('object_type') + table.columns.hide('object') + + return table + + # # Tenant groups #