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>
94 lines
3.7 KiB
Python
94 lines
3.7 KiB
Python
"""Verwaltung der Branding-Profile in der NetBox-Oberfläche."""
|
||
from django.contrib import messages
|
||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||
from django.http import HttpResponse
|
||
from django.shortcuts import get_object_or_404, redirect, render
|
||
from django.utils import timezone
|
||
from django.views import View
|
||
|
||
from .blocks import KV, P, T, Document, H
|
||
from .branding import _normalize
|
||
from .forms import BrandingProfileForm
|
||
from .models import BrandingProfile
|
||
from .renderers.html import render_html
|
||
|
||
APP = "netbox_customer_export"
|
||
|
||
|
||
class BrandingListView(PermissionRequiredMixin, View):
|
||
permission_required = f"{APP}.view_brandingprofile"
|
||
|
||
def get(self, request):
|
||
return render(request, f"{APP}/branding_list.html", {"profiles": BrandingProfile.objects.all()})
|
||
|
||
|
||
class BrandingEditView(PermissionRequiredMixin, View):
|
||
template_name = f"{APP}/branding_edit.html"
|
||
|
||
def get_permission_required(self):
|
||
return [f"{APP}.{'change' if self.kwargs.get('pk') else 'add'}_brandingprofile"]
|
||
|
||
def _obj(self, pk):
|
||
return get_object_or_404(BrandingProfile, pk=pk) if pk else BrandingProfile()
|
||
|
||
def get(self, request, pk=None):
|
||
obj = self._obj(pk)
|
||
return render(request, self.template_name, {"object": obj, "form": BrandingProfileForm(instance=obj)})
|
||
|
||
def post(self, request, pk=None):
|
||
obj = self._obj(pk)
|
||
form = BrandingProfileForm(request.POST, request.FILES, instance=obj)
|
||
if form.is_valid():
|
||
obj = form.save()
|
||
messages.success(request, f"Branding-Profil „{obj}“ gespeichert.")
|
||
return redirect(f"plugins:{APP}:branding_list")
|
||
return render(request, self.template_name, {"object": obj, "form": form})
|
||
|
||
|
||
class BrandingDeleteView(PermissionRequiredMixin, View):
|
||
permission_required = f"{APP}.delete_brandingprofile"
|
||
|
||
def get(self, request, pk):
|
||
return render(request, f"{APP}/branding_delete.html", {"object": get_object_or_404(BrandingProfile, pk=pk)})
|
||
|
||
def post(self, request, pk):
|
||
obj = get_object_or_404(BrandingProfile, pk=pk)
|
||
name = str(obj)
|
||
for f in (obj.logo, obj.docx_template):
|
||
if f:
|
||
f.delete(save=False)
|
||
obj.delete()
|
||
messages.success(request, f"Branding-Profil „{name}“ gelöscht.")
|
||
return redirect(f"plugins:{APP}:branding_list")
|
||
|
||
|
||
class BrandingPreviewView(PermissionRequiredMixin, View):
|
||
"""Beispieldokument (HTML) mit dem Profil – zum Prüfen von Farben und Logo."""
|
||
|
||
permission_required = f"{APP}.view_brandingprofile"
|
||
|
||
def get(self, request, pk):
|
||
obj = get_object_or_404(BrandingProfile, pk=pk)
|
||
blocks = [
|
||
H(1, "Übersicht"),
|
||
KV([("Standort", "Musterstandort"), ("Status", "Aktiv"), ("Anschrift", "Musterstraße 1\n12345 Musterstadt")]),
|
||
H(2, "Geräte"),
|
||
T(
|
||
["Name", "Hersteller / Modell", "Rack / HE", "Management-IP"],
|
||
[
|
||
["SW-CORE-01", "HPE Aruba 6100", "Rack A / HE 20", "10.0.0.2/24"],
|
||
["SW-ACC-01", "HPE Aruba 6000", "Rack A / HE 18", "10.0.0.3/24"],
|
||
["FW-01", "Sophos XGS 2100", "Rack A / HE 16", "10.0.0.1/24"],
|
||
],
|
||
),
|
||
P("So sehen Überschriften, Tabellen und Fließtext mit diesem Profil aus."),
|
||
]
|
||
doc = Document(
|
||
title="Netzwerkdokumentation Vorschau",
|
||
subtitle="Beispielkunde",
|
||
blocks=blocks,
|
||
meta={"author": request.user.username, "date": timezone.localtime().strftime("%d.%m.%Y")},
|
||
branding=_normalize(obj.as_branding()),
|
||
)
|
||
return HttpResponse(render_html(doc), content_type="text/html; charset=utf-8")
|