feat: ZIP-Export auf durchsuchbare Ordnerauswahl umstellen

This commit is contained in:
2026-07-22 12:41:44 +02:00
parent c586e9fdaa
commit 0492c67b9f
7 changed files with 40 additions and 13 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ class DocumentationConfig(PluginConfig):
name = "netbox_documentation"
verbose_name = "NetBox Dokumentation"
description = "Wiki und Office-Dokumentation direkt in NetBox"
version = "0.4.0"
version = "0.4.1"
author = "LKE"
base_url = "documentation"
min_version = "4.0.0"
+14
View File
@@ -20,6 +20,20 @@ class ArchiveFailure(ValueError):
pass
def documents_for_categories(categories, include_subfolders=True, user=None):
"""Return distinct permitted documents contained in the selected category trees."""
category_ids = set(categories.values_list("pk", flat=True))
frontier = set(category_ids)
while include_subfolders and frontier:
children = set(DocumentCategory.objects.filter(parent_id__in=frontier).values_list("pk", flat=True))
frontier = children - category_ids
category_ids.update(children)
documents = Document.objects.filter(category_id__in=category_ids).distinct().order_by("title")
if user is not None:
documents = documents.restrict(user, "view")
return documents
def _category_path(category):
path, seen = [], set()
while category and category.pk not in seen:
+13 -6
View File
@@ -3,7 +3,9 @@ from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from utilities.forms import get_field_value
from utilities.forms.fields import ContentTypeChoiceField, DynamicModelChoiceField, SlugField
from utilities.forms.fields import (
ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField,
)
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import HTMXSelect
from netbox.forms import NetBoxModelForm
@@ -119,17 +121,22 @@ class ImportForm(forms.Form):
class ArchiveExportForm(forms.Form):
documents = forms.ModelMultipleChoiceField(
queryset=Document.objects.none(), widget=forms.CheckboxSelectMultiple,
label="Dokumentationen",
categories = DynamicModelMultipleChoiceField(
queryset=DocumentCategory.objects.all(), selector=True,
label="Ordner und Kategorien",
help_text="Einen oder mehrere Ordner suchen und hinzufügen.",
)
include_subfolders = forms.BooleanField(
required=False, initial=True, label="Unterordner einbeziehen",
help_text="Exportiert Dokumentationen aus allen untergeordneten Ordnern.",
)
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
queryset = Document.objects.all().order_by("title")
queryset = DocumentCategory.objects.all().order_by("name")
if user is not None:
queryset = queryset.restrict(user, "view")
self.fields["documents"].queryset = queryset
self.fields["categories"].queryset = queryset
class ArchiveImportForm(forms.Form):
@@ -9,7 +9,7 @@
<div class="card h-100">
<h5 class="card-header"><i class="mdi mdi-folder-zip"></i> Dokumentationen exportieren</h5>
<div class="card-body">
<p>Ausgewählte Dokumentationen gemeinsam mit Ordnern, Objektzuordnungen und Anhängen herunterladen.</p>
<p>Mehrere Ordner suchen und hinzufügen. Alle enthaltenen Dokumentationen werden gemeinsam mit Objektzuordnungen und Anhängen heruntergeladen.</p>
<form method="post">
{% csrf_token %}
<input type="hidden" name="action" value="export">
+8 -2
View File
@@ -16,7 +16,7 @@ from .forms import (
ArchiveExportForm, ArchiveImportForm, AssignmentForm, DocumentCategoryForm,
DocumentForm, ImportForm,
)
from .archive import ArchiveFailure, export_documents, import_archive
from .archive import ArchiveFailure, documents_for_categories, export_documents, import_archive
from .importers import ImportFailure, import_document
from .models import Document, DocumentAssignment, DocumentAttachment, DocumentCategory
from .tables import DocumentTable, AssignmentTable, DocumentCategoryTable
@@ -189,7 +189,13 @@ class DocumentArchiveView(View):
form = ArchiveExportForm(request.POST, user=request.user)
if not form.is_valid():
return self._render(request, export_form=form)
stream = export_documents(form.cleaned_data["documents"])
documents = documents_for_categories(
form.cleaned_data["categories"], form.cleaned_data["include_subfolders"], request.user
)
if not documents.exists():
form.add_error("categories", "Die ausgewählten Ordner enthalten keine exportierbaren Dokumentationen.")
return self._render(request, export_form=form)
stream = export_documents(documents)
response = FileResponse(stream, content_type="application/zip")
response["Content-Disposition"] = 'attachment; filename="netbox-documentation-export.zip"'
return response