194 lines
7.2 KiB
Python
194 lines
7.2 KiB
Python
from django.contrib import messages
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from netbox.views import generic
|
|
from utilities.views import register_model_view
|
|
|
|
from .engine.resolver import Resolver
|
|
from .filtersets import ServiceFilterSet, ServiceTemplateFilterSet
|
|
from .forms import (
|
|
ResolveForm,
|
|
ServiceBulkEditForm,
|
|
ServiceFilterSetForm,
|
|
ServiceForm,
|
|
ServiceTemplateBulkEditForm,
|
|
ServiceTemplateFilterSetForm,
|
|
ServiceTemplateForm,
|
|
ServiceTemplateImportForm,
|
|
)
|
|
from .models import Service, ServiceTemplate
|
|
from .tables import ServiceTable, ServiceTemplateTable
|
|
|
|
|
|
def _build_preview(result):
|
|
"""Transform result.planned_objects into a list of dicts with pre-computed action."""
|
|
preview = []
|
|
for node_name, obj in result.planned_objects:
|
|
ct = ContentType.objects.get_for_model(obj.__class__)
|
|
key = (ct.id, obj.pk)
|
|
action = "add" if key in result.to_add else "keep"
|
|
preview.append({"node": node_name, "object": obj, "action": action})
|
|
return preview
|
|
|
|
|
|
# ════════════════════════════════════════════════════════════════════
|
|
# Service Template
|
|
# ════════════════════════════════════════════════════════════════════
|
|
|
|
@register_model_view(ServiceTemplate, "list", path="", detail=False)
|
|
class ServiceTemplateListView(generic.ObjectListView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
table = ServiceTemplateTable
|
|
filterset = ServiceTemplateFilterSet
|
|
filterset_form = ServiceTemplateFilterSetForm
|
|
|
|
|
|
@register_model_view(ServiceTemplate, "add", path="add", detail=False)
|
|
@register_model_view(ServiceTemplate, "edit")
|
|
class ServiceTemplateEditView(generic.ObjectEditView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
form = ServiceTemplateForm
|
|
|
|
|
|
@register_model_view(ServiceTemplate, "delete")
|
|
class ServiceTemplateDeleteView(generic.ObjectDeleteView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
|
|
|
|
@register_model_view(ServiceTemplate, "bulk_edit", path="edit", detail=False)
|
|
class ServiceTemplateBulkEditView(generic.BulkEditView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
table = ServiceTemplateTable
|
|
form = ServiceTemplateBulkEditForm
|
|
|
|
|
|
@register_model_view(ServiceTemplate, "bulk_delete", path="delete", detail=False)
|
|
class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
table = ServiceTemplateTable
|
|
|
|
|
|
@register_model_view(ServiceTemplate, "bulk_import", path="import", detail=False)
|
|
class ServiceTemplateBulkImportView(generic.BulkImportView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
model_form = ServiceTemplateImportForm
|
|
table = ServiceTemplateTable
|
|
|
|
|
|
@register_model_view(ServiceTemplate)
|
|
class ServiceTemplateView(generic.ObjectView):
|
|
queryset = ServiceTemplate.objects.all()
|
|
|
|
def get_extra_context(self, request, instance):
|
|
context = super().get_extra_context(request, instance)
|
|
context["is_locked"] = instance.is_locked
|
|
return context
|
|
|
|
|
|
# ════════════════════════════════════════════════════════════════════
|
|
# Service
|
|
# ════════════════════════════════════════════════════════════════════
|
|
|
|
@register_model_view(Service, "list", path="", detail=False)
|
|
class ServiceListView(generic.ObjectListView):
|
|
queryset = Service.objects.all()
|
|
table = ServiceTable
|
|
filterset = ServiceFilterSet
|
|
filterset_form = ServiceFilterSetForm
|
|
|
|
|
|
@register_model_view(Service, "add", path="add", detail=False)
|
|
@register_model_view(Service, "edit")
|
|
class ServiceEditView(generic.ObjectEditView):
|
|
queryset = Service.objects.all()
|
|
form = ServiceForm
|
|
|
|
|
|
@register_model_view(Service, "delete")
|
|
class ServiceDeleteView(generic.ObjectDeleteView):
|
|
queryset = Service.objects.all()
|
|
|
|
|
|
@register_model_view(Service, "bulk_edit", path="edit", detail=False)
|
|
class ServiceBulkEditView(generic.BulkEditView):
|
|
queryset = Service.objects.all()
|
|
table = ServiceTable
|
|
form = ServiceBulkEditForm
|
|
|
|
|
|
@register_model_view(Service, "bulk_delete", path="delete", detail=False)
|
|
class ServiceBulkDeleteView(generic.BulkDeleteView):
|
|
queryset = Service.objects.all()
|
|
table = ServiceTable
|
|
|
|
|
|
@register_model_view(Service)
|
|
class ServiceView(generic.ObjectView):
|
|
queryset = Service.objects.all()
|
|
|
|
def get_extra_context(self, request, instance):
|
|
context = super().get_extra_context(request, instance)
|
|
context["bindings"] = instance.bindings.select_related(
|
|
"content_type",
|
|
).all()
|
|
return context
|
|
|
|
|
|
@register_model_view(Service, "resolve", path="resolve")
|
|
class ServiceResolveView(generic.ObjectView):
|
|
"""Dry-run preview (GET) and commit (POST) for service resolution."""
|
|
|
|
queryset = Service.objects.all()
|
|
|
|
def get(self, request, pk):
|
|
service = get_object_or_404(self.queryset, pk=pk)
|
|
resolver = Resolver()
|
|
try:
|
|
result = resolver.resolve(service, mode="dry_run", user=request.user)
|
|
except Exception as exc:
|
|
messages.error(request, f"Resolution failed: {exc}")
|
|
return redirect("plugins:netbox_services:service", pk=service.pk)
|
|
|
|
return render(request, "netbox_services/service_resolve.html", {
|
|
"object": service,
|
|
"service": service,
|
|
"result": result,
|
|
"planned_preview": _build_preview(result),
|
|
"form": ResolveForm(initial={"mode": "commit"}),
|
|
"active_tab": "resolve",
|
|
})
|
|
|
|
def post(self, request, pk):
|
|
service = get_object_or_404(self.queryset, pk=pk)
|
|
form = ResolveForm(request.POST)
|
|
mode = form.cleaned_data.get("mode", "dry_run") if form.is_valid() else "dry_run"
|
|
|
|
resolver = Resolver()
|
|
try:
|
|
result = resolver.resolve(service, mode=mode, user=request.user)
|
|
except Exception as exc:
|
|
messages.error(request, f"Resolution failed: {exc}")
|
|
return redirect("plugins:netbox_services:service", pk=service.pk)
|
|
|
|
if mode == "commit":
|
|
messages.success(
|
|
request,
|
|
_("Resolution committed: {added} added, {removed} removed, {kept} unchanged.").format(
|
|
added=len(result.to_add),
|
|
removed=len(result.to_remove),
|
|
kept=result.total_planned - len(result.to_add),
|
|
),
|
|
)
|
|
return redirect("plugins:netbox_services:service", pk=service.pk)
|
|
|
|
return render(request, "netbox_services/service_resolve.html", {
|
|
"object": service,
|
|
"service": service,
|
|
"result": result,
|
|
"planned_preview": _build_preview(result),
|
|
"form": ResolveForm(initial={"mode": "commit"}),
|
|
"active_tab": "resolve",
|
|
})
|