Files
NetBox-Customer-Export/netbox_customer_export/forms.py
T
MrBlakeandClaude Opus 5.5 8f45bffa99 NetBox Customer Export plugin with configurable branding
Plugin for NetBox 4.6.8–4.6.99 that exports customer documentation
(PDF, Word, HTML preview) for a site, location, tenant or tenant group.
Technicians pick sections, device roles and columns before exporting.

Branding profiles (colors, font, logo, footer, Word template incl. .dotx,
table style, extra CSS) are configurable via PLUGINS_CONFIG and selectable
per export.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:43:19 +02:00

80 lines
3.8 KiB
Python

from django import forms
from dcim.models import DeviceRole, Location, Site
from netbox.plugins import get_plugin_config
from tenancy.models import Tenant, TenantGroup
from utilities.forms.fields import DynamicModelChoiceField
from .branding import get_brandings
from .sections import DEFAULT_DEVICE_COLUMNS, DEVICE_COLUMNS, SECTIONS
FORMAT_CHOICES = (("pdf", "PDF"), ("docx", "Word (.docx)"), ("html", "HTML-Vorschau"))
class ScopeSelectForm(forms.Form):
site = DynamicModelChoiceField(queryset=Site.objects.all(), required=False, label="Standort")
location = DynamicModelChoiceField(queryset=Location.objects.all(), required=False, label="Lokation")
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, label="Mandant")
tenantgroup = DynamicModelChoiceField(queryset=TenantGroup.objects.all(), required=False, label="Mandantengruppe")
def clean(self):
data = super().clean()
chosen = [(k, v) for k, v in data.items() if v]
if len(chosen) != 1:
raise forms.ValidationError("Bitte genau einen Scope auswählen.")
data["kind"], data["obj"] = chosen[0]
return data
class ExportForm(forms.Form):
format = forms.ChoiceField(choices=FORMAT_CHOICES, initial="pdf", label="Format")
title = forms.CharField(max_length=200, label="Titel")
subtitle = forms.CharField(max_length=200, required=False, label="Untertitel")
author = forms.CharField(max_length=100, required=False, label="Erstellt von")
branding = forms.ChoiceField(choices=(), label="Design / Firma")
sections = forms.MultipleChoiceField(
choices=[(s.key, s.label) for s in SECTIONS.values()],
initial=[s.key for s in SECTIONS.values() if s.default],
widget=forms.CheckboxSelectMultiple,
label="Inhalte",
)
roles = forms.ModelMultipleChoiceField(
queryset=DeviceRole.objects.none(), required=False, widget=forms.CheckboxSelectMultiple, label="Geräterollen"
)
device_columns = forms.MultipleChoiceField(
choices=[(k, v[0]) for k, v in DEVICE_COLUMNS.items()],
initial=DEFAULT_DEVICE_COLUMNS,
required=False,
widget=forms.CheckboxSelectMultiple,
label="Gerätespalten",
)
group_by_site = forms.BooleanField(required=False, initial=True, label="Geräte nach Standort gruppieren")
rack_svg = forms.BooleanField(required=False, initial=True, label="Rack-Ansichten (SVG) einbetten")
rack_faces = forms.MultipleChoiceField(
choices=(("front", "Vorderseite"), ("rear", "Rückseite")),
initial=["front"],
required=False,
widget=forms.CheckboxSelectMultiple,
label="Rack-Seiten",
)
rack_devices = forms.BooleanField(required=False, initial=True, label="Geräteliste je Rack")
rack_pagebreak = forms.BooleanField(required=False, initial=True, label="Seitenumbruch nach jedem Rack")
include_empty = forms.BooleanField(required=False, label="Leere Abschnitte trotzdem aufführen")
include_secrets = forms.BooleanField(required=False, label="Geheimnisse (z.B. WLAN-PSK) mit exportieren")
def __init__(self, *args, scope=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields["branding"].choices = [(k, b["name"]) for k, b in get_brandings().items()]
if scope is not None:
role_ids = scope.devices().values("role")
roles = DeviceRole.objects.filter(pk__in=role_ids).order_by("name")
self.fields["roles"].queryset = roles
self.fields["roles"].initial = list(roles)
self.fields["title"].initial = f"Netzwerkdokumentation {scope.obj}"
self.fields["subtitle"].initial = f"{scope.label}: {scope.obj}"
if not get_plugin_config("netbox_customer_export", "allow_secrets"):
del self.fields["include_secrets"]