diff --git a/README.md b/README.md
index d44afe1..6e3f71c 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ A plugin designed to faciliate the storage of site, circuit, device type and dev
- Locations
- Virtual Machines
- Circuit Providers
+ - Power Panels
* Upload documents to your NetBox media/ folder or other Django supported storage method e.g. S3
* Supports a wide array of common file types (bmp, gif, jpeg, jpg, png, pdf, txt, doc, docx, xls, xlsx, xlsm)
diff --git a/netbox_documents/__init__.py b/netbox_documents/__init__.py
index ba1d1c4..65a5602 100644
--- a/netbox_documents/__init__.py
+++ b/netbox_documents/__init__.py
@@ -17,6 +17,7 @@ class NetboxDocuments(PluginConfig):
"enable_device_type_documents": True,
"enable_vm_documents": True,
"enable_circuit_provider_documents": True,
+ "enable_power_panel_documents": True,
"enable_navigation_menu": True,
"site_documents_location": "left",
"location_documents_location": "left",
@@ -25,6 +26,7 @@ class NetboxDocuments(PluginConfig):
"device_type_documents_location": "left",
"vm_documents_location": "left",
"circuit_provider_documents_location": "left",
+ "power_panel_documents_location": "left",
}
config = NetboxDocuments
diff --git a/netbox_documents/api/serializers.py b/netbox_documents/api/serializers.py
index 69489e1..8c6346e 100644
--- a/netbox_documents/api/serializers.py
+++ b/netbox_documents/api/serializers.py
@@ -1,8 +1,8 @@
from rest_framework import serializers
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
-from ..models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument
-from dcim.api.nested_serializers import NestedSiteSerializer, NestedLocationSerializer, NestedDeviceSerializer, NestedDeviceTypeSerializer
+from ..models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument, PowerPanelDocument
+from dcim.api.nested_serializers import NestedSiteSerializer, NestedLocationSerializer, NestedDeviceSerializer, NestedDeviceTypeSerializer, NestedPowerPanelSerializer
from circuits.api.nested_serializers import NestedCircuitSerializer, NestedProviderSerializer
from virtualization.api.nested_serializers import NestedVirtualMachineSerializer
from .fields import UploadableBase64FileField
@@ -199,4 +199,33 @@ class Meta:
model = CircuitProviderDocument
fields = (
'id', 'url', 'display', 'name', 'document', 'external_url', 'document_type', 'filename',
- )
\ No newline at end of file
+ )
+
+# Power Panel Document Serializer
+class PowerPanelDocumentSerializer(NetBoxModelSerializer):
+
+ url = serializers.HyperlinkedIdentityField(
+ view_name='plugins-api:netbox_documents-api:powerpaneldocument-detail'
+ )
+
+ powerpanel = NestedPowerPanelSerializer()
+ document = UploadableBase64FileField(required=False)
+
+ class Meta:
+ model = PowerPanelDocument
+ fields = (
+ 'id', 'url', 'display', 'name', 'document', 'external_url', 'document_type', 'filename', 'powerpanel', 'comments', 'tags', 'custom_fields', 'created',
+ 'last_updated',
+ )
+
+class NestedPowerPanelDocumentSerializer(WritableNestedSerializer):
+
+ url = serializers.HyperlinkedIdentityField(
+ view_name='plugins-api:netbox_documents-api:powerpanel-detail'
+ )
+
+ class Meta:
+ model = PowerPanelDocument
+ fields = (
+ 'id', 'url', 'display', 'name', 'document', 'external_url', 'document_type', 'filename',
+ )
diff --git a/netbox_documents/api/urls.py b/netbox_documents/api/urls.py
index 4034248..7dedabd 100644
--- a/netbox_documents/api/urls.py
+++ b/netbox_documents/api/urls.py
@@ -11,5 +11,6 @@
router.register('circuit-documents', views.CircuitDocumentViewSet)
router.register('vm-documents', views.VMDocumentViewSet)
router.register('circuitprovider-documents', views.CircuitProviderDocumentViewSet)
+router.register('powerpanel-documents', views.PowerPanelDocumentViewSet)
urlpatterns = router.urls
\ No newline at end of file
diff --git a/netbox_documents/api/views.py b/netbox_documents/api/views.py
index 6de627c..7e80380 100644
--- a/netbox_documents/api/views.py
+++ b/netbox_documents/api/views.py
@@ -1,7 +1,7 @@
from netbox.api.viewsets import NetBoxModelViewSet
from .. import models, filtersets
-from .serializers import SiteDocumentSerializer, LocationDocumentSerializer, DeviceDocumentSerializer, DeviceTypeDocumentSerializer, CircuitDocumentSerializer, VMDocumentSerializer, CircuitProviderDocumentSerializer
+from .serializers import SiteDocumentSerializer, LocationDocumentSerializer, DeviceDocumentSerializer, DeviceTypeDocumentSerializer, CircuitDocumentSerializer, VMDocumentSerializer, CircuitProviderDocumentSerializer, PowerPanelDocumentSerializer
class SiteDocumentViewSet(NetBoxModelViewSet):
queryset = models.SiteDocument.objects.prefetch_related('tags')
@@ -36,4 +36,9 @@ class VMDocumentViewSet(NetBoxModelViewSet):
class CircuitProviderDocumentViewSet(NetBoxModelViewSet):
queryset = models.CircuitProviderDocument.objects.prefetch_related('tags')
serializer_class = CircuitProviderDocumentSerializer
- filterset_class = filtersets.CircuitProviderDocumentFilterSet
\ No newline at end of file
+ filterset_class = filtersets.CircuitProviderDocumentFilterSet
+
+class PowerPanelDocumentViewSet(NetBoxModelViewSet):
+ queryset = models.PowerPanelDocument.objects.prefetch_related('tags')
+ serializer_class = PowerPanelDocumentSerializer
+ filterset_class = filtersets.PowerPanelDocumentFilterSet
diff --git a/netbox_documents/filtersets.py b/netbox_documents/filtersets.py
index 7284127..1c64b40 100644
--- a/netbox_documents/filtersets.py
+++ b/netbox_documents/filtersets.py
@@ -1,5 +1,5 @@
from netbox.filtersets import NetBoxModelFilterSet
-from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument
+from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument, PowerPanelDocument
from django.db.models import Q
class SiteDocumentFilterSet(NetBoxModelFilterSet):
@@ -86,7 +86,7 @@ def search(self, queryset, name, value):
Q(name__icontains=value) |
Q(document__icontains=value)
)
-
+
class CircuitProviderDocumentFilterSet(NetBoxModelFilterSet):
class Meta:
@@ -99,4 +99,18 @@ def search(self, queryset, name, value):
return queryset.filter(
Q(name__icontains=value) |
Q(document__icontains=value)
- )
\ No newline at end of file
+ )
+
+class PowerPanelDocumentFilterSet(NetBoxModelFilterSet):
+
+ class Meta:
+ model = PowerPanelDocument
+ fields = ('id', 'name', 'document_type', 'powerpanel')
+
+ def search(self, queryset, name, value):
+ if not value.strip():
+ return queryset
+ return queryset.filter(
+ Q(name__icontains=value) |
+ Q(document__icontains=value)
+ )
diff --git a/netbox_documents/forms.py b/netbox_documents/forms.py
index a29eee8..25c28d8 100644
--- a/netbox_documents/forms.py
+++ b/netbox_documents/forms.py
@@ -1,10 +1,10 @@
from django import forms
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm
-from dcim.models import Site, Location, Device, DeviceType
+from dcim.models import Site, Location, Device, DeviceType, PowerPanel
from virtualization.models import VirtualMachine
from circuits.models import Circuit, Provider
from utilities.forms.fields import TagFilterField, CommentField, DynamicModelChoiceField
-from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, CircuitDocTypeChoices, SiteDocTypeChoices, LocationDocTypeChoices, DeviceDocTypeChoices, DeviceTypeDocTypeChoices, VMDocument, VMDocTypeChoices, CircuitProviderDocument, CircuitProviderDocTypeChoices
+from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, CircuitDocTypeChoices, SiteDocTypeChoices, LocationDocTypeChoices, DeviceDocTypeChoices, DeviceTypeDocTypeChoices, VMDocument, VMDocTypeChoices, CircuitProviderDocument, CircuitProviderDocTypeChoices, PowerPanelDocument, PowerPanelDocTypeChoices
#### Site Document Form & Filter Form
@@ -241,4 +241,35 @@ class CircuitProviderDocumentFilterForm(NetBoxModelFilterSetForm):
required=False
)
- tag = TagFilterField(model)
\ No newline at end of file
+ tag = TagFilterField(model)
+
+#### Power Panel Document Form & Filter Form
+class PowerPanelDocumentForm(NetBoxModelForm):
+ comments = CommentField()
+
+ powerpanel = DynamicModelChoiceField(
+ queryset=PowerPanel.objects.all()
+ )
+
+ class Meta:
+ model = PowerPanelDocument
+ fields = ('name', 'document', 'external_url', 'document_type', 'powerpanel', 'comments', 'tags')
+
+class PowerPanelDocumentFilterForm(NetBoxModelFilterSetForm):
+ model = PowerPanelDocument
+
+ name = forms.CharField(
+ required=False
+ )
+
+ powerpanel = forms.ModelMultipleChoiceField(
+ queryset=PowerPanel.objects.all(),
+ required=False
+ )
+
+ document_type = forms.MultipleChoiceField(
+ choices=PowerPanelDocTypeChoices,
+ required=False
+ )
+
+ tag = TagFilterField(model)
diff --git a/netbox_documents/migrations/0007_circuitproviderdocument.py b/netbox_documents/migrations/0007_circuitproviderdocument.py
index afa4961..bc99507 100644
--- a/netbox_documents/migrations/0007_circuitproviderdocument.py
+++ b/netbox_documents/migrations/0007_circuitproviderdocument.py
@@ -10,7 +10,6 @@
class Migration(migrations.Migration):
dependencies = [
- ('extras', '0107_cachedvalue_extras_cachedvalue_object'),
('circuits', '0043_circuittype_color'),
('netbox_documents', '0006_vmdocument'),
]
diff --git a/netbox_documents/migrations/0008_powerpaneldocument.py b/netbox_documents/migrations/0008_powerpaneldocument.py
new file mode 100644
index 0000000..b480d7c
--- /dev/null
+++ b/netbox_documents/migrations/0008_powerpaneldocument.py
@@ -0,0 +1,40 @@
+# Generated by Django 4.2.9 on 2024-04-18 13:16
+
+from django.db import migrations, models
+import django.db.models.deletion
+import netbox_documents.utils
+import taggit.managers
+import utilities.json
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('dcim', '0185_gfk_indexes'),
+ ('extras', '0106_bookmark_user_cascade_deletion'),
+ ('netbox_documents', '0007_circuitproviderdocument'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='PowerPanelDocument',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
+ ('created', models.DateTimeField(auto_now_add=True, null=True)),
+ ('last_updated', models.DateTimeField(auto_now=True, null=True)),
+ ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
+ ('name', models.CharField(blank=True, max_length=100)),
+ ('document', models.FileField(blank=True, upload_to=netbox_documents.utils.file_upload)),
+ ('external_url', models.URLField(blank=True, max_length=255)),
+ ('document_type', models.CharField(max_length=30)),
+ ('comments', models.TextField(blank=True)),
+ ('powerpanel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='dcim.powerpanel')),
+ ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+ ],
+ options={
+ 'verbose_name': 'Power Panel Document',
+ 'verbose_name_plural': 'Power Panel Documents',
+ 'ordering': ('name',),
+ },
+ ),
+ ]
diff --git a/netbox_documents/models.py b/netbox_documents/models.py
index 5fc5348..6d980cf 100644
--- a/netbox_documents/models.py
+++ b/netbox_documents/models.py
@@ -98,6 +98,15 @@ class VMDocTypeChoices(ChoiceSet):
('other', 'Other', 'gray'),
]
+class PowerPanelDocTypeChoices(ChoiceSet):
+
+ key = 'DocTypeChoices.circuit'
+
+ CHOICES = [
+ ('schematic', 'Electrical Schematic', 'red'),
+ ('other', 'Other', 'gray'),
+ ]
+
class SiteDocument(NetBoxModel):
name = models.CharField(
max_length=100,
@@ -855,4 +864,110 @@ def delete(self, *args, **kwargs):
self.document.name = _name
else:
# Straight delete of external URL
- super().delete(*args, **kwargs)
\ No newline at end of file
+ super().delete(*args, **kwargs)
+
+
+class PowerPanelDocument(NetBoxModel):
+ name = models.CharField(
+ max_length=100,
+ blank=True,
+ help_text='(Optional) Specify a name to display for this document. If no name is specified, the filename will be used.'
+ )
+
+ document = models.FileField(
+ upload_to=file_upload,
+ blank=True
+ )
+
+ external_url = models.URLField(
+ blank=True,
+ max_length=255
+ )
+
+ document_type = models.CharField(
+ max_length=30,
+ choices=PowerPanelDocTypeChoices
+ )
+
+ powerpanel = models.ForeignKey(
+ to='dcim.PowerPanel',
+ on_delete=models.CASCADE,
+ related_name='documents'
+ )
+
+ comments = models.TextField(
+ blank=True
+ )
+
+ def get_document_type_color(self):
+ return PowerPanelDocTypeChoices.colors.get(self.document_type)
+
+ class Meta:
+ ordering = ('name',)
+ verbose_name_plural = "Power Panel Documents"
+ verbose_name = "Power Panel Document"
+
+ @property
+ def size(self):
+ """
+ Wrapper around `document.size` to suppress an OSError in case the file is inaccessible. Also opportunistically
+ catch other exceptions that we know other storage back-ends to throw.
+ """
+ expected_exceptions = [OSError]
+
+ try:
+ from botocore.exceptions import ClientError
+ expected_exceptions.append(ClientError)
+ except ImportError:
+ pass
+
+ try:
+ return self.document.size
+ except:
+ return None
+
+ @property
+ def filename(self):
+ if self.external_url:
+ return self.external_url
+ filename = self.document.name.rsplit('/', 1)[-1]
+ return filename.split('_', 1)[1]
+
+ def __str__(self):
+ if self.name:
+ return self.name
+
+ if self.external_url:
+ return self.external_url
+
+ filename = self.document.name.rsplit('/', 1)[-1]
+ return filename.split('_', 1)[1]
+
+ def get_absolute_url(self):
+ return reverse('plugins:netbox_documents:powerpaneldocument', args=[self.pk])
+
+ def clean(self):
+ super().clean()
+
+ # Must have an uploaded document or an external URL. cannot have both
+ if not self.document and self.external_url == '':
+ raise ValidationError("A document must contain an uploaded file or an external URL.")
+ if self.document and self.external_url:
+ raise ValidationError("A document cannot contain both an uploaded file and an external URL.")
+
+ def delete(self, *args, **kwargs):
+
+ # Check if its a document or a URL
+ if self.external_url == '':
+
+ _name = self.document.name
+
+ # Delete file from disk
+ super().delete(*args, **kwargs)
+ self.document.delete(save=False)
+
+ # Restore the name of the document as it's re-used in the notifications later
+ self.document.name = _name
+ else:
+ # Straight delete of external URL
+ super().delete(*args, **kwargs)
diff --git a/netbox_documents/navigation.py b/netbox_documents/navigation.py
index 2c56576..f25dd02 100644
--- a/netbox_documents/navigation.py
+++ b/netbox_documents/navigation.py
@@ -124,6 +124,21 @@
)
)
+ # Add a menu item for Power Panel Documents if enabled
+ if plugin_settings.get('enable_power_panel_documents'):
+ menuitem.append(
+ PluginMenuItem(
+ link='plugins:netbox_documents:powerpaneldocument_list',
+ link_text='Power Panel Documents',
+ buttons=[PluginMenuButton(
+ link='plugins:netbox_documents:powerpaneldocument_add',
+ title='Add',
+ icon_class='mdi mdi-plus-thick',
+ color=ButtonColorChoices.GREEN
+ )]
+ )
+ )
+
else:
# Fall back to pre 3.4 navigation option
diff --git a/netbox_documents/search.py b/netbox_documents/search.py
index 22e81f6..1e29b86 100644
--- a/netbox_documents/search.py
+++ b/netbox_documents/search.py
@@ -1,5 +1,5 @@
from netbox.search import SearchIndex
-from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument
+from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument, PowerPanelDocument
from django.conf import settings
# If we run NB 3.4+ register search indexes
@@ -60,5 +60,13 @@ class CircuitProviderDocumentIndex(SearchIndex):
("comments", 5000),
)
+ class PowerPanelDocumentIndex(SearchIndex):
+ model = PowerPanelDocument
+ fields = (
+ ("name", 100),
+ ("document", 500),
+ ("comments", 5000),
+ )
+
# Register indexes
- indexes = [SiteDocumentIndex, LocationDocumentIndex, CircuitDocumentIndex, DeviceTypeDocumentIndex, DeviceDocumentIndex, VMDocumentIndex, CircuitProviderDocumentIndex]
\ No newline at end of file
+ indexes = [SiteDocumentIndex, LocationDocumentIndex, CircuitDocumentIndex, DeviceTypeDocumentIndex, DeviceDocumentIndex, VMDocumentIndex, CircuitProviderDocumentIndex, PowerPanelDocumentIndex]
\ No newline at end of file
diff --git a/netbox_documents/tables.py b/netbox_documents/tables.py
index a2aba3a..75f718d 100644
--- a/netbox_documents/tables.py
+++ b/netbox_documents/tables.py
@@ -1,7 +1,7 @@
import django_tables2 as tables
from netbox.tables import NetBoxTable, columns
-from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument
+from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, PowerPanelDocument
SITE_DOCUMENT_LINK = """
{% if record.size %}
@@ -59,6 +59,14 @@
{% endif %}
"""
+POWER_PANEL_DOCUMENT_LINK = """
+{% if record.size %}
+ {% firstof record.name record.filename %} (View Document)
+{% else %}
+ {% firstof record.name record.filename %} (View External Document)
+{% endif %}
+"""
+
class SiteDocumentTable(NetBoxTable):
name = tables.TemplateColumn(template_code=SITE_DOCUMENT_LINK)
document_type = columns.ChoiceFieldColumn()
@@ -91,7 +99,7 @@ class LocationDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = LocationDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'site', 'location', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'site', 'location', 'comments', 'actions', 'created', 'last_updated', 'tags')
default_columns = ('name', 'document_type', 'site', 'location', 'tags')
class DeviceDocumentTable(NetBoxTable):
@@ -107,7 +115,7 @@ class DeviceDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = DeviceDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'device', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'device', 'comments', 'actions', 'created', 'last_updated', 'tags')
default_columns = ('name', 'document_type', 'device', 'tags')
@@ -124,7 +132,7 @@ class DeviceTypeDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = DeviceTypeDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'device_type', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'device_type', 'comments', 'actions', 'created', 'last_updated', 'tags')
default_columns = ('name', 'document_type', 'device_type', 'tags')
class CircuitDocumentTable(NetBoxTable):
@@ -140,7 +148,7 @@ class CircuitDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = CircuitDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'circuit', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'circuit', 'comments', 'actions', 'created', 'last_updated', 'tags')
default_columns = ('name', 'document_type', 'circuit', 'tags')
class VMDocumentTable(NetBoxTable):
@@ -156,7 +164,7 @@ class VMDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = VMDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'vm', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'vm', 'comments', 'actions', 'created', 'last_updated', 'tags')
default_columns = ('name', 'document_type', 'vm', 'tags')
class CircuitProviderDocumentTable(NetBoxTable):
@@ -172,5 +180,21 @@ class CircuitProviderDocumentTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = CircuitDocument
- fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'provider', 'comments', 'actions', 'created', 'last_updated', 'tags')
- default_columns = ('name', 'document_type', 'provider', 'tags')
\ No newline at end of file
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'provider', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ default_columns = ('name', 'document_type', 'provider', 'tags')
+
+class PowerPanelDocumentTable(NetBoxTable):
+ name = tables.TemplateColumn(template_code=POWER_PANEL_DOCUMENT_LINK)
+ document_type = columns.ChoiceFieldColumn()
+ powerpanel = tables.Column(
+ linkify=True
+ )
+
+ tags = columns.TagColumn(
+ url_name='dcim:sitegroup_list'
+ )
+
+ class Meta(NetBoxTable.Meta):
+ model = CircuitDocument
+ fields = ('pk', 'id', 'name', 'document_type', 'size', 'filename', 'powerpanel', 'comments', 'actions', 'created', 'last_updated', 'tags')
+ default_columns = ('name', 'document_type', 'powerpanel', 'tags')
\ No newline at end of file
diff --git a/netbox_documents/template_content.py b/netbox_documents/template_content.py
index a632685..3dbd8a2 100644
--- a/netbox_documents/template_content.py
+++ b/netbox_documents/template_content.py
@@ -1,6 +1,6 @@
from extras.plugins import PluginTemplateExtension
from django.conf import settings
-from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument
+from .models import SiteDocument, LocationDocument, DeviceDocument, DeviceTypeDocument, CircuitDocument, VMDocument, CircuitProviderDocument, PowerPanelDocument
plugin_settings = settings.PLUGINS_CONFIG.get('netbox_documents', {})
@@ -182,5 +182,29 @@ def right_page(self):
else:
return ""
+class PowerPanelDocumentList(PluginTemplateExtension):
+ model = 'dcim.powerpanel'
-template_extensions = [SiteDocumentList, LocationDocumentList, DeviceDocumentList, DeviceTypeDocumentList, CircuitDocumentList, VMDocumentList, CircuitProviderDocumentList]
+ def left_page(self):
+
+ if plugin_settings.get('enable_power_panel_documents') and plugin_settings.get('power_panel_documents_location') == 'left':
+
+ return self.render('netbox_documents/powerpaneldocument_include.html', extra_context={
+ 'powerpanel_documents': PowerPanelDocument.objects.filter(powerpanel=self.context['object']),
+ })
+
+ else:
+ return ""
+
+ def right_page(self):
+
+ if plugin_settings.get('enable_power_panel_documents') and plugin_settings.get('power_panel_documents_location') == 'right':
+
+ return self.render('netbox_documents/powerpaneldocument_include.html', extra_context={
+ 'powerpanel_documents': PowerPanelDocument.objects.filter(powerpanel=self.context['object']),
+ })
+
+ else:
+ return ""
+
+template_extensions = [SiteDocumentList, LocationDocumentList, DeviceDocumentList, DeviceTypeDocumentList, CircuitDocumentList, VMDocumentList, CircuitProviderDocumentList, PowerPanelDocumentList]
diff --git a/netbox_documents/templates/netbox_documents/powerpaneldocument.html b/netbox_documents/templates/netbox_documents/powerpaneldocument.html
new file mode 100644
index 0000000..72e2b6c
--- /dev/null
+++ b/netbox_documents/templates/netbox_documents/powerpaneldocument.html
@@ -0,0 +1,56 @@
+{% extends 'generic/object.html' %}
+{% load helpers %}
+{% load plugins %}
+
+{% block content %}
+
+
+
+
+
+
+
+ Name |
+ {{ object.name|placeholder }} |
+
+
+ Power Panel |
+ {{ object.powerpanel }} |
+
+
+ Document Type |
+ {% badge object.get_document_type_display bg_color=object.get_document_type_color %} |
+
+ {% if object.external_url %}
+
+ External URL |
+ {{ object.external_url }} |
+
+ {% else %}
+
+ Filename |
+ {{ object.filename }} |
+
+
+ Size |
+ {{ object.size|filesizeformat }} |
+
+ {% endif %}
+
+
+
+ {% include 'inc/panels/custom_fields.html' %}
+ {% plugin_left_page object %}
+
+
+ {% include 'inc/panels/tags.html' %}
+ {% include 'inc/panels/comments.html' %}
+ {% plugin_right_page object %}
+
+
+
+
+ {% plugin_full_width_page object %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/netbox_documents/templates/netbox_documents/powerpaneldocument_edit.html b/netbox_documents/templates/netbox_documents/powerpaneldocument_edit.html
new file mode 100644
index 0000000..ad8fbcc
--- /dev/null
+++ b/netbox_documents/templates/netbox_documents/powerpaneldocument_edit.html
@@ -0,0 +1,49 @@
+{% extends 'generic/object_edit.html' %}
+{% load static %}
+{% load form_helpers %}
+{% load helpers %}
+
+{% block form %}
+
+ {% render_field form.name %}
+
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+ {% render_field form.document %}
+
+
+ {% render_field form.external_url %}
+
+
+
+ {% render_field form.document_type %}
+ {% render_field form.powerpanel %}
+
+
+
+
Comments
+
+ {% render_field form.comments %}
+
+
+ {% render_field form.tags %}
+
+
+{% endblock %}
diff --git a/netbox_documents/templates/netbox_documents/powerpaneldocument_include.html b/netbox_documents/templates/netbox_documents/powerpaneldocument_include.html
new file mode 100644
index 0000000..7066b04
--- /dev/null
+++ b/netbox_documents/templates/netbox_documents/powerpaneldocument_include.html
@@ -0,0 +1,49 @@
+{% load helpers %}
+
+
+
+
+{% if powerpanel_documents %}
+
+ {% else %}
+
+ None
+
+ {% endif %}
+
+
+
\ No newline at end of file
diff --git a/netbox_documents/urls.py b/netbox_documents/urls.py
index dd35681..03cf2c6 100644
--- a/netbox_documents/urls.py
+++ b/netbox_documents/urls.py
@@ -63,7 +63,7 @@
path('vm-document//delete/', views.VMDocumentDeleteView.as_view(), name='vmdocument_delete'),
path('vm-document//changelog/', ObjectChangeLogView.as_view(), name='vmdocument_changelog', kwargs={
'model': models.VMDocument
- }),
+ }),
# CircuitProviderDocument
path('circuitprovider-document/', views.CircuitProviderDocumentListView.as_view(), name='circuitproviderdocument_list'),
@@ -73,7 +73,16 @@
path('circuitprovider-document//delete/', views.CircuitProviderDocumentDeleteView.as_view(), name='circuitproviderdocument_delete'),
path('circuitprovider-document//changelog/', ObjectChangeLogView.as_view(), name='circuitproviderdocument_changelog', kwargs={
'model': models.CircuitProviderDocument
- }),
-
+ }),
+
+ # PowerPanelDocument
+ path('powerpanel-document/', views.PowerPanelDocumentListView.as_view(), name='powerpaneldocument_list'),
+ path('powerpanel-document/add/', views.PowerPanelDocumentEditView.as_view(), name='powerpaneldocument_add'),
+ path('powerpanel-document//', views.PowerPanelDocumentView.as_view(), name='powerpaneldocument'),
+ path('powerpanel-document//edit/', views.PowerPanelDocumentEditView.as_view(), name='powerpaneldocument_edit'),
+ path('powerpanel-document//delete/', views.PowerPanelDocumentDeleteView.as_view(), name='powerpaneldocument_delete'),
+ path('powerpanel-document//changelog/', ObjectChangeLogView.as_view(), name='powerpaneldocument_changelog', kwargs={
+ 'model': models.PowerPanelDocument
+ }),
)
\ No newline at end of file
diff --git a/netbox_documents/utils.py b/netbox_documents/utils.py
index fcf9f14..41faeb5 100644
--- a/netbox_documents/utils.py
+++ b/netbox_documents/utils.py
@@ -22,6 +22,8 @@ def file_upload(instance, filename):
path_prepend = instance.vm.id
if hasattr(instance, 'provider'):
path_prepend = instance.provider.id
+ if hasattr(instance, 'powerpanel'):
+ path_prepend = instance.powerpanel.id
# Rename the file to the provided name, if any. Attempt to preserve the file extension.
extension = filename.rsplit('.')[-1].lower()
diff --git a/netbox_documents/views.py b/netbox_documents/views.py
index bcf383a..0fbe7c7 100644
--- a/netbox_documents/views.py
+++ b/netbox_documents/views.py
@@ -137,4 +137,23 @@ class CircuitProviderDocumentEditView(generic.ObjectEditView):
template_name = 'netbox_documents/circuitproviderdocument_edit.html'
class CircuitProviderDocumentDeleteView(generic.ObjectDeleteView):
- queryset = models.CircuitProviderDocument.objects.all()
\ No newline at end of file
+ queryset = models.CircuitProviderDocument.objects.all()
+
+### PowerPanelDocument
+class PowerPanelDocumentView(generic.ObjectView):
+ queryset = models.PowerPanelDocument.objects.all()
+
+class PowerPanelDocumentListView(generic.ObjectListView):
+ queryset = models.PowerPanelDocument.objects.all()
+ table = tables.PowerPanelDocumentTable
+ filterset = filtersets.PowerPanelDocumentFilterSet
+ filterset_form = forms.PowerPanelDocumentFilterForm
+
+class PowerPanelDocumentEditView(generic.ObjectEditView):
+ queryset = models.PowerPanelDocument.objects.all()
+ form = forms.PowerPanelDocumentForm
+
+ template_name = 'netbox_documents/powerpaneldocument_edit.html'
+
+class PowerPanelDocumentDeleteView(generic.ObjectDeleteView):
+ queryset = models.PowerPanelDocument.objects.all()
\ No newline at end of file