Files
NetBox-Customer-Export/netbox_customer_export/models.py
T
MrBlakeandClaude Opus 5.5 f24e42a516 feat: manage branding profiles in the NetBox UI
New BrandingProfile model (migration 0001) with logo upload, color
pickers, font, Word template upload, table style and extra CSS, plus
list/edit/delete views, an HTML preview and a menu entry with add
button. Access is controlled via the model's Django permissions.

Profiles from the database are offered first in the export form (the
default profile preselected); profiles from PLUGINS_CONFIG still work.

Bump version to 0.2.0 - requires "manage.py migrate".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:21:11 +02:00

77 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.core.validators import FileExtensionValidator, MaxValueValidator, MinValueValidator, RegexValidator
from django.db import models
from django.urls import reverse
hex_color = RegexValidator(r"^[0-9A-Fa-f]{6}$", "Hex-Farbe ohne # erwartet, z.B. 1F4E79")
def _color(default, verbose_name):
return models.CharField(max_length=6, default=default, validators=[hex_color], verbose_name=verbose_name)
class BrandingProfile(models.Model):
"""In NetBox gepflegtes Design-Profil (Alternative/Ergänzung zu PLUGINS_CONFIG['brandings'])."""
name = models.CharField(max_length=100, unique=True, verbose_name="Name")
is_default = models.BooleanField(default=False, verbose_name="Standardprofil")
company_name = models.CharField(max_length=200, blank=True, verbose_name="Firmenname")
footer_text = models.CharField(
max_length=300, blank=True, default="Vertraulich – nur für den internen Gebrauch des Kunden", verbose_name="Fußzeile"
)
logo = models.ImageField(upload_to="customer-export/logos/", blank=True, verbose_name="Logo")
primary_color = _color("1F4E79", "Primärfarbe")
accent_color = _color("2E75B6", "Akzentfarbe")
header_text_color = _color("FFFFFF", "Schrift Tabellenkopf")
label_bg_color = _color("DEEAF6", "Hintergrund Beschriftungen")
stripe_color = _color("F3F7FB", "Zebrastreifen")
font_family = models.CharField(max_length=100, default="Calibri", verbose_name="Schriftart")
font_size = models.PositiveSmallIntegerField(
default=10, validators=[MinValueValidator(7), MaxValueValidator(16)], verbose_name="Schriftgröße (pt)"
)
docx_template = models.FileField(
upload_to="customer-export/templates/",
blank=True,
validators=[FileExtensionValidator(["docx", "dotx"])],
verbose_name="Word-Vorlage",
)
docx_table_style = models.CharField(max_length=100, blank=True, verbose_name="Tabellenformatvorlage (Word)")
extra_css = models.TextField(blank=True, verbose_name="Zusätzliches CSS (PDF/HTML)")
last_updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ("-is_default", "name")
verbose_name = "Branding-Profil"
verbose_name_plural = "Branding-Profile"
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("plugins:netbox_customer_export:branding_edit", kwargs={"pk": self.pk})
def save(self, *args, **kwargs):
for field in ("primary_color", "accent_color", "header_text_color", "label_bg_color", "stripe_color"):
setattr(self, field, getattr(self, field).lstrip("#").upper())
super().save(*args, **kwargs)
if self.is_default:
BrandingProfile.objects.exclude(pk=self.pk).filter(is_default=True).update(is_default=False)
def as_branding(self):
"""Dict im Format von branding.DEFAULT_BRANDING."""
return {
"name": self.name,
"company_name": self.company_name,
"footer_text": self.footer_text,
"logo_path": self.logo.path if self.logo else None,
"primary_color": self.primary_color,
"accent_color": self.accent_color,
"header_text_color": self.header_text_color,
"label_bg_color": self.label_bg_color,
"stripe_color": self.stripe_color,
"font_family": self.font_family,
"font_size": self.font_size,
"docx_template": self.docx_template.path if self.docx_template else None,
"docx_table_style": self.docx_table_style,
"extra_css": self.extra_css,
}