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>
130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
"""Ermittelt, welche Objekte zu einem Export-Scope (Standort, Lokation, Mandant, Mandantengruppe) gehören."""
|
|
from django.db.models import Q
|
|
|
|
from circuits.models import Circuit
|
|
from dcim.models import Device, Location, PowerFeed, Rack, Site
|
|
from ipam.models import VLAN, VRF, IPAddress, Prefix
|
|
from tenancy.models import Tenant, TenantGroup
|
|
from virtualization.models import VirtualMachine
|
|
from wireless.models import WirelessLAN
|
|
|
|
SCOPE_MODELS = {
|
|
"site": Site,
|
|
"location": Location,
|
|
"tenant": Tenant,
|
|
"tenantgroup": TenantGroup,
|
|
}
|
|
|
|
SCOPE_LABELS = {
|
|
"site": "Standort",
|
|
"location": "Lokation",
|
|
"tenant": "Mandant",
|
|
"tenantgroup": "Mandantengruppe",
|
|
}
|
|
|
|
NONE = Q(pk__in=[])
|
|
|
|
|
|
class Scope:
|
|
def __init__(self, kind, obj, user):
|
|
self.kind = kind
|
|
self.obj = obj
|
|
self.user = user
|
|
self.label = SCOPE_LABELS[kind]
|
|
self.locations = None
|
|
self.tenants = None
|
|
if kind == "location":
|
|
self.locations = obj.get_descendants(include_self=True)
|
|
elif kind == "tenant":
|
|
self.tenants = Tenant.objects.filter(pk=obj.pk)
|
|
elif kind == "tenantgroup":
|
|
self.tenants = Tenant.objects.filter(group__in=obj.get_descendants(include_self=True))
|
|
|
|
# -- Hilfsfunktionen --------------------------------------------------
|
|
|
|
def restrict(self, qs):
|
|
if hasattr(qs, "restrict"):
|
|
return qs.restrict(self.user, "view")
|
|
return qs
|
|
|
|
def _q(self, site=(), location=(), tenant=("tenant",)):
|
|
"""Baut einen Q-Filter; jedes Argument ist eine Liste von Feldpfaden, die ODER-verknüpft werden."""
|
|
if self.kind == "site":
|
|
paths, value = site, self.obj
|
|
elif self.kind == "location":
|
|
paths, value = [f"{p}__in" for p in location], self.locations
|
|
else:
|
|
paths, value = [f"{p}__in" for p in tenant], self.tenants
|
|
q = NONE
|
|
for p in paths:
|
|
q |= Q(**{p: value})
|
|
return q
|
|
|
|
def _qs(self, model, **paths):
|
|
return self.restrict(model.objects.filter(self._q(**paths)).distinct())
|
|
|
|
# -- Objekte ----------------------------------------------------------
|
|
|
|
def sites(self):
|
|
if self.kind == "site":
|
|
return self.restrict(Site.objects.filter(pk=self.obj.pk))
|
|
if self.kind == "location":
|
|
return self.restrict(Site.objects.filter(pk=self.obj.site_id))
|
|
return self._qs(Site, tenant=("tenant", "devices__tenant", "racks__tenant"))
|
|
|
|
def location_objects(self):
|
|
return self._qs(Location, site=("site",), location=("pk",), tenant=("tenant", "devices__tenant"))
|
|
|
|
def racks(self):
|
|
return self._qs(Rack, site=("site",), location=("location",), tenant=("tenant", "devices__tenant"))
|
|
|
|
def devices(self):
|
|
return self._qs(Device, site=("site",), location=("location",))
|
|
|
|
def virtual_machines(self):
|
|
return self._qs(
|
|
VirtualMachine,
|
|
site=("site", "cluster___site"),
|
|
location=("cluster___location", "device__location"),
|
|
)
|
|
|
|
def prefixes(self):
|
|
return self._qs(Prefix, site=("_site",), location=("_location",))
|
|
|
|
def vlans(self):
|
|
return self._qs(
|
|
VLAN,
|
|
site=("site", "prefixes___site"),
|
|
location=(
|
|
"prefixes___location",
|
|
"interfaces_as_untagged__device__location",
|
|
"interfaces_as_tagged__device__location",
|
|
),
|
|
)
|
|
|
|
def vrfs(self):
|
|
q = Q(prefixes__in=self.prefixes())
|
|
if self.tenants is not None:
|
|
q |= Q(tenant__in=self.tenants)
|
|
return self.restrict(VRF.objects.filter(q).distinct())
|
|
|
|
def ip_addresses(self):
|
|
q = Q(interface__device__in=self.devices()) | Q(vminterface__virtual_machine__in=self.virtual_machines())
|
|
if self.tenants is not None:
|
|
q |= Q(tenant__in=self.tenants)
|
|
return self.restrict(IPAddress.objects.filter(q).distinct())
|
|
|
|
def circuits(self):
|
|
return self._qs(Circuit, site=("terminations___site",), location=("terminations___location",))
|
|
|
|
def wireless_lans(self):
|
|
return self._qs(WirelessLAN, site=("_site",), location=("_location",))
|
|
|
|
def power_feeds(self):
|
|
return self._qs(PowerFeed, site=("power_panel__site",), location=("power_panel__location",))
|
|
|
|
def tenant_objects(self):
|
|
if self.tenants is not None:
|
|
return self.restrict(self.tenants)
|
|
return self.restrict(Tenant.objects.filter(devices__in=self.devices()).distinct())
|