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>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user