Explorar o código

Fixes: #18305 make contacts mixin available for plugins (#19029)

Renato Almeida de Oliveira hai 10 meses
pai
achega
864db469ba

+ 2 - 0
docs/plugins/development/models.md

@@ -117,6 +117,8 @@ For more information about database migrations, see the [Django documentation](h
 
 
 ::: netbox.models.features.CloningMixin
 ::: netbox.models.features.CloningMixin
 
 
+::: netbox.models.features.ContactsMixin
+
 ::: netbox.models.features.CustomLinksMixin
 ::: netbox.models.features.CustomLinksMixin
 
 
 ::: netbox.models.features.CustomFieldsMixin
 ::: netbox.models.features.CustomFieldsMixin

+ 0 - 16
netbox/circuits/views.py

@@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _
 
 
 from dcim.views import PathTraceView
 from dcim.views import PathTraceView
 from netbox.views import generic
 from netbox.views import generic
-from tenancy.views import ObjectContactsView
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.query import count_related
 from utilities.query import count_related
 from utilities.views import GetRelatedModelsMixin, register_model_view
 from utilities.views import GetRelatedModelsMixin, register_model_view
@@ -74,11 +73,6 @@ class ProviderBulkDeleteView(generic.BulkDeleteView):
     table = tables.ProviderTable
     table = tables.ProviderTable
 
 
 
 
-@register_model_view(Provider, 'contacts')
-class ProviderContactsView(ObjectContactsView):
-    queryset = Provider.objects.all()
-
-
 #
 #
 # ProviderAccounts
 # ProviderAccounts
 #
 #
@@ -141,11 +135,6 @@ class ProviderAccountBulkDeleteView(generic.BulkDeleteView):
     table = tables.ProviderAccountTable
     table = tables.ProviderAccountTable
 
 
 
 
-@register_model_view(ProviderAccount, 'contacts')
-class ProviderAccountContactsView(ObjectContactsView):
-    queryset = ProviderAccount.objects.all()
-
-
 #
 #
 # Provider networks
 # Provider networks
 #
 #
@@ -413,11 +402,6 @@ class CircuitSwapTerminations(generic.ObjectEditView):
         })
         })
 
 
 
 
-@register_model_view(Circuit, 'contacts')
-class CircuitContactsView(ObjectContactsView):
-    queryset = Circuit.objects.all()
-
-
 #
 #
 # Circuit terminations
 # Circuit terminations
 #
 #

+ 0 - 41
netbox/dcim/views.py

@@ -19,7 +19,6 @@ from ipam.models import ASN, IPAddress, Prefix, VLANGroup
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
 from netbox.views import generic
 from netbox.views import generic
-from tenancy.views import ObjectContactsView
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.permissions import get_permission_for_model
 from utilities.permissions import get_permission_for_model
@@ -304,11 +303,6 @@ class RegionBulkDeleteView(generic.BulkDeleteView):
     table = tables.RegionTable
     table = tables.RegionTable
 
 
 
 
-@register_model_view(Region, 'contacts')
-class RegionContactsView(ObjectContactsView):
-    queryset = Region.objects.all()
-
-
 #
 #
 # Site groups
 # Site groups
 #
 #
@@ -412,11 +406,6 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView):
     table = tables.SiteGroupTable
     table = tables.SiteGroupTable
 
 
 
 
-@register_model_view(SiteGroup, 'contacts')
-class SiteGroupContactsView(ObjectContactsView):
-    queryset = SiteGroup.objects.all()
-
-
 #
 #
 # Sites
 # Sites
 #
 #
@@ -494,11 +483,6 @@ class SiteBulkDeleteView(generic.BulkDeleteView):
     table = tables.SiteTable
     table = tables.SiteTable
 
 
 
 
-@register_model_view(Site, 'contacts')
-class SiteContactsView(ObjectContactsView):
-    queryset = Site.objects.all()
-
-
 #
 #
 # Locations
 # Locations
 #
 #
@@ -596,11 +580,6 @@ class LocationBulkDeleteView(generic.BulkDeleteView):
     table = tables.LocationTable
     table = tables.LocationTable
 
 
 
 
-@register_model_view(Location, 'contacts')
-class LocationContactsView(ObjectContactsView):
-    queryset = Location.objects.all()
-
-
 #
 #
 # Rack roles
 # Rack roles
 #
 #
@@ -887,11 +866,6 @@ class RackBulkDeleteView(generic.BulkDeleteView):
     table = tables.RackTable
     table = tables.RackTable
 
 
 
 
-@register_model_view(Rack, 'contacts')
-class RackContactsView(ObjectContactsView):
-    queryset = Rack.objects.all()
-
-
 #
 #
 # Rack reservations
 # Rack reservations
 #
 #
@@ -1029,11 +1003,6 @@ class ManufacturerBulkDeleteView(generic.BulkDeleteView):
     table = tables.ManufacturerTable
     table = tables.ManufacturerTable
 
 
 
 
-@register_model_view(Manufacturer, 'contacts')
-class ManufacturerContactsView(ObjectContactsView):
-    queryset = Manufacturer.objects.all()
-
-
 #
 #
 # Device types
 # Device types
 #
 #
@@ -2360,11 +2329,6 @@ class DeviceBulkRenameView(generic.BulkRenameView):
     table = tables.DeviceTable
     table = tables.DeviceTable
 
 
 
 
-@register_model_view(Device, 'contacts')
-class DeviceContactsView(ObjectContactsView):
-    queryset = Device.objects.all()
-
-
 #
 #
 # Modules
 # Modules
 #
 #
@@ -3924,11 +3888,6 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView):
     table = tables.PowerPanelTable
     table = tables.PowerPanelTable
 
 
 
 
-@register_model_view(PowerPanel, 'contacts')
-class PowerPanelContactsView(ObjectContactsView):
-    queryset = PowerPanel.objects.all()
-
-
 #
 #
 # Power feeds
 # Power feeds
 #
 #

+ 0 - 26
netbox/ipam/views.py

@@ -11,7 +11,6 @@ from dcim.forms import InterfaceFilterForm
 from dcim.models import Interface, Site
 from dcim.models import Interface, Site
 from ipam.tables import VLANTranslationRuleTable
 from ipam.tables import VLANTranslationRuleTable
 from netbox.views import generic
 from netbox.views import generic
-from tenancy.views import ObjectContactsView
 from utilities.query import count_related
 from utilities.query import count_related
 from utilities.tables import get_table_ordering
 from utilities.tables import get_table_ordering
 from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
 from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
@@ -434,11 +433,6 @@ class AggregateBulkDeleteView(generic.BulkDeleteView):
     table = tables.AggregateTable
     table = tables.AggregateTable
 
 
 
 
-@register_model_view(Aggregate, 'contacts')
-class AggregateContactsView(ObjectContactsView):
-    queryset = Aggregate.objects.all()
-
-
 #
 #
 # Prefix/VLAN roles
 # Prefix/VLAN roles
 #
 #
@@ -684,11 +678,6 @@ class PrefixBulkDeleteView(generic.BulkDeleteView):
     table = tables.PrefixTable
     table = tables.PrefixTable
 
 
 
 
-@register_model_view(Prefix, 'contacts')
-class PrefixContactsView(ObjectContactsView):
-    queryset = Prefix.objects.all()
-
-
 #
 #
 # IP Ranges
 # IP Ranges
 #
 #
@@ -778,11 +767,6 @@ class IPRangeBulkDeleteView(generic.BulkDeleteView):
     table = tables.IPRangeTable
     table = tables.IPRangeTable
 
 
 
 
-@register_model_view(IPRange, 'contacts')
-class IPRangeContactsView(ObjectContactsView):
-    queryset = IPRange.objects.all()
-
-
 #
 #
 # IP addresses
 # IP addresses
 #
 #
@@ -964,11 +948,6 @@ class IPAddressRelatedIPsView(generic.ObjectChildrenView):
         return parent.get_related_ips().restrict(request.user, 'view')
         return parent.get_related_ips().restrict(request.user, 'view')
 
 
 
 
-@register_model_view(IPAddress, 'contacts')
-class IPAddressContactsView(ObjectContactsView):
-    queryset = IPAddress.objects.all()
-
-
 #
 #
 # VLAN groups
 # VLAN groups
 #
 #
@@ -1476,8 +1455,3 @@ class ServiceBulkDeleteView(generic.BulkDeleteView):
     queryset = Service.objects.prefetch_related('device', 'virtual_machine')
     queryset = Service.objects.prefetch_related('device', 'virtual_machine')
     filterset = filtersets.ServiceFilterSet
     filterset = filtersets.ServiceFilterSet
     table = tables.ServiceTable
     table = tables.ServiceTable
-
-
-@register_model_view(Service, 'contacts')
-class ServiceContactsView(ObjectContactsView):
-    queryset = Service.objects.all()

+ 7 - 2
netbox/netbox/models/features.py

@@ -353,7 +353,7 @@ class ImageAttachmentsMixin(models.Model):
 
 
 class ContactsMixin(models.Model):
 class ContactsMixin(models.Model):
     """
     """
-    Enables the assignments of Contacts (via ContactAssignment).
+    Enables the assignment of Contacts to a model (via ContactAssignment).
     """
     """
     contacts = GenericRelation(
     contacts = GenericRelation(
         to='tenancy.ContactAssignment',
         to='tenancy.ContactAssignment',
@@ -368,7 +368,8 @@ class ContactsMixin(models.Model):
         """
         """
         Return a `QuerySet` matching all contacts assigned to this object.
         Return a `QuerySet` matching all contacts assigned to this object.
 
 
-        :param inherited: If `True`, inherited contacts from parent objects are included.
+        Args:
+            inherited: If `True`, inherited contacts from parent objects are included.
         """
         """
         from tenancy.models import ContactAssignment
         from tenancy.models import ContactAssignment
         from . import NestedGroupModel
         from . import NestedGroupModel
@@ -659,6 +660,10 @@ def register_models(*models):
                 )
                 )
 
 
         # Register applicable feature views for the model
         # Register applicable feature views for the model
+        if issubclass(model, ContactsMixin):
+            register_model_view(model, 'contacts', kwargs={'model': model})(
+                'netbox.views.generic.ObjectContactsView'
+            )
         if issubclass(model, JournalingMixin):
         if issubclass(model, JournalingMixin):
             register_model_view(model, 'journal', kwargs={'model': model})(
             register_model_view(model, 'journal', kwargs={'model': model})(
                 'netbox.views.generic.ObjectJournalView'
                 'netbox.views.generic.ObjectJournalView'

+ 28 - 0
netbox/netbox/views/generic/feature_views.py

@@ -12,13 +12,19 @@ from core.tables import JobTable, ObjectChangeTable
 from extras.forms import JournalEntryForm
 from extras.forms import JournalEntryForm
 from extras.models import JournalEntry
 from extras.models import JournalEntry
 from extras.tables import JournalEntryTable
 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.permissions import get_permission_for_model
 from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab
 from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab
 from .base import BaseMultiObjectView
 from .base import BaseMultiObjectView
+from .object_views import ObjectChildrenView
 
 
 __all__ = (
 __all__ = (
     'BulkSyncDataView',
     'BulkSyncDataView',
     'ObjectChangeLogView',
     'ObjectChangeLogView',
+    'ObjectContactsView',
     'ObjectJobsView',
     'ObjectJobsView',
     'ObjectJournalView',
     'ObjectJournalView',
     'ObjectSyncDataView',
     'ObjectSyncDataView',
@@ -244,3 +250,25 @@ class BulkSyncDataView(GetReturnURLMixin, BaseMultiObjectView):
             ))
             ))
 
 
         return redirect(self.get_return_url(request))
         return redirect(self.get_return_url(request))
+
+
+class ObjectContactsView(ObjectChildrenView):
+    child_model = ContactAssignment
+    table = ContactAssignmentTable
+    filterset = ContactAssignmentFilterSet
+    filterset_form = ContactAssignmentFilterForm
+    template_name = 'tenancy/object_contacts.html'
+    tab = ViewTab(
+        label=_('Contacts'),
+        badge=lambda obj: obj.get_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 parent.get_contacts().restrict(request.user, 'view').order_by('priority', 'contact', 'role')

+ 1 - 24
netbox/tenancy/views.py

@@ -1,31 +1,13 @@
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.shortcuts import get_object_or_404
 from django.shortcuts import get_object_or_404
-from django.utils.translation import gettext_lazy as _
 
 
 from netbox.views import generic
 from netbox.views import generic
 from utilities.query import count_related
 from utilities.query import count_related
-from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
+from utilities.views import GetRelatedModelsMixin, register_model_view
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
 from .models import *
 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.get_contacts().count(),
-        permission='tenancy.view_contactassignment',
-        weight=5000
-    )
-
-    def get_children(self, request, parent):
-        return parent.get_contacts().restrict(request.user, 'view').order_by('priority', 'contact', 'role')
-
-
 #
 #
 # Tenant groups
 # Tenant groups
 #
 #
@@ -156,11 +138,6 @@ class TenantBulkDeleteView(generic.BulkDeleteView):
     table = tables.TenantTable
     table = tables.TenantTable
 
 
 
 
-@register_model_view(Tenant, 'contacts')
-class TenantContactsView(ObjectContactsView):
-    queryset = Tenant.objects.all()
-
-
 #
 #
 # Contact groups
 # Contact groups
 #
 #

+ 0 - 16
netbox/virtualization/views.py

@@ -16,7 +16,6 @@ from ipam.models import IPAddress
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
 from netbox.views import generic
 from netbox.views import generic
-from tenancy.views import ObjectContactsView
 from utilities.query import count_related
 from utilities.query import count_related
 from utilities.query_functions import CollateAsChar
 from utilities.query_functions import CollateAsChar
 from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
 from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
@@ -148,11 +147,6 @@ class ClusterGroupBulkDeleteView(generic.BulkDeleteView):
     table = tables.ClusterGroupTable
     table = tables.ClusterGroupTable
 
 
 
 
-@register_model_view(ClusterGroup, 'contacts')
-class ClusterGroupContactsView(ObjectContactsView):
-    queryset = ClusterGroup.objects.all()
-
-
 #
 #
 # Clusters
 # Clusters
 #
 #
@@ -344,11 +338,6 @@ class ClusterRemoveDevicesView(generic.ObjectEditView):
         })
         })
 
 
 
 
-@register_model_view(Cluster, 'contacts')
-class ClusterContactsView(ObjectContactsView):
-    queryset = Cluster.objects.all()
-
-
 #
 #
 # Virtual machines
 # Virtual machines
 #
 #
@@ -509,11 +498,6 @@ class VirtualMachineBulkDeleteView(generic.BulkDeleteView):
     table = tables.VirtualMachineTable
     table = tables.VirtualMachineTable
 
 
 
 
-@register_model_view(VirtualMachine, 'contacts')
-class VirtualMachineContactsView(ObjectContactsView):
-    queryset = VirtualMachine.objects.all()
-
-
 #
 #
 # VM interfaces
 # VM interfaces
 #
 #

+ 0 - 6
netbox/vpn/views.py

@@ -1,6 +1,5 @@
 from ipam.tables import RouteTargetTable
 from ipam.tables import RouteTargetTable
 from netbox.views import generic
 from netbox.views import generic
-from tenancy.views import ObjectContactsView
 from utilities.query import count_related
 from utilities.query import count_related
 from utilities.views import GetRelatedModelsMixin, register_model_view
 from utilities.views import GetRelatedModelsMixin, register_model_view
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
@@ -497,11 +496,6 @@ class L2VPNBulkDeleteView(generic.BulkDeleteView):
     table = tables.L2VPNTable
     table = tables.L2VPNTable
 
 
 
 
-@register_model_view(L2VPN, 'contacts')
-class L2VPNContactsView(ObjectContactsView):
-    queryset = L2VPN.objects.all()
-
-
 #
 #
 # L2VPN terminations
 # L2VPN terminations
 #
 #