Skip to content

Commit a19c4a2

Browse files
committed
Netbox 4.1 support
1 parent c63dbad commit a19c4a2

File tree

19 files changed

+101
-76
lines changed

19 files changed

+101
-76
lines changed

netbox_script_manager/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
__version__ = "0.4.0"
66

77

8-
from extras.plugins import PluginConfig
8+
from netbox.plugins import PluginConfig
99

1010

1111
class NetboxScriptManagerConfig(PluginConfig):

netbox_script_manager/api/serializers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from netbox.api.serializers import NetBoxModelSerializer
77
from netbox.config import get_config
88
from rest_framework import serializers
9-
from tenancy.api.nested_serializers import NestedTenantSerializer
9+
from tenancy.api.serializers import TenantSerializer
1010
from utilities.templatetags.builtins.filters import render_markdown
1111

1212
from netbox_script_manager.choices import ScriptExecutionStatusChoices
@@ -34,7 +34,7 @@ def to_representation(self, value):
3434
class ScriptInstanceSerializer(NetBoxModelSerializer):
3535
url = serializers.HyperlinkedIdentityField(view_name="plugins-api:netbox_script_manager-api:scriptinstance-detail")
3636
name = serializers.CharField(required=True)
37-
tenant = NestedTenantSerializer(required=False, allow_null=True)
37+
tenant = TenantSerializer(required=False, allow_null=True, nested=True)
3838

3939
class Meta:
4040
model = ScriptInstance

netbox_script_manager/api/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from rest_framework.response import Response
1515
from rest_framework.routers import APIRootView
1616
from utilities.permissions import get_permission_for_model
17-
from utilities.utils import copy_safe_request
17+
from utilities.request import copy_safe_request
1818

1919
from .. import util
2020
from ..choices import ScriptExecutionStatusChoices

netbox_script_manager/forms.py

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from django import forms
2-
from django.contrib.auth.models import User
2+
from users.models import User
33
from django.utils.translation import gettext as _
44
from extras.choices import DurationChoices
5-
from extras.forms.mixins import SavedFiltersMixin
5+
from netbox.forms.mixins import SavedFiltersMixin
66
from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm
77
from tenancy.models import Tenant
8-
from utilities.forms import BootstrapMixin, FilterForm
8+
from utilities.forms import FilterForm
99
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
1010
from utilities.forms.widgets import APISelectMultiple, DateTimePicker, NumberWithOptions
11-
from utilities.utils import local_now
11+
from utilities.datetime import local_now
12+
from utilities.forms.rendering import FieldSet
1213

1314
from .choices import ScriptExecutionStatusChoices
1415
from .models import ScriptExecution, ScriptInstance
@@ -57,20 +58,18 @@ class ScriptInstanceFilterForm(NetBoxModelFilterSetForm):
5758

5859
class ScriptExecutionFilterForm(SavedFiltersMixin, FilterForm):
5960
fieldsets = (
60-
(None, ("q", "filter_id")),
61-
(
62-
"Creation",
63-
(
64-
"created__before",
65-
"created__after",
66-
"scheduled__before",
67-
"scheduled__after",
68-
"started__before",
69-
"started__after",
70-
"completed__before",
71-
"completed__after",
72-
"user",
73-
),
61+
FieldSet("q", "filter_id", name="Query Filters"),
62+
FieldSet(
63+
"created__before",
64+
"created__after",
65+
"scheduled__before",
66+
"scheduled__after",
67+
"started__before",
68+
"started__after",
69+
"completed__before",
70+
"completed__after",
71+
"user",
72+
name="Creation and Timing",
7473
),
7574
)
7675
model = ScriptExecution
@@ -94,7 +93,7 @@ class ScriptExecutionFilterForm(SavedFiltersMixin, FilterForm):
9493
)
9594

9695

97-
class ScriptForm(BootstrapMixin, forms.Form):
96+
class ScriptForm(forms.Form):
9897
default_renderer = forms.renderers.DjangoTemplates()
9998

10099
_commit = forms.BooleanField(
@@ -126,6 +125,20 @@ def __init__(self, *args, scheduling_enabled=True, **kwargs):
126125
now = local_now().strftime("%Y-%m-%d %H:%M:%S")
127126
self.fields["_schedule_at"].help_text += f" (current time: <strong>{now}</strong>)"
128127

128+
# Stupid workaround for the insanely hacky netbox core code mentioned in #16293
129+
# We can't use the default form renderer because it messes up checkboxes,
130+
# so we have to manually inject the form-control class into all input fields.
131+
for field in self.fields.values():
132+
widget_type = type(field.widget)
133+
if issubclass(widget_type, forms.widgets.Input) or issubclass(widget_type, forms.widgets.Textarea):
134+
if hasattr(field.widget, "input_type") and field.widget.input_type == "checkbox":
135+
continue
136+
137+
if "class" in field.widget.attrs:
138+
field.widget.attrs["class"] += " form-control"
139+
else:
140+
field.widget.attrs["class"] = "form-control"
141+
129142
# Remove scheduling fields if scheduling is disabled
130143
if not scheduling_enabled:
131144
self.fields.pop("_schedule_at")

netbox_script_manager/models.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
import django_rq
77
from django.conf import settings
8-
from django.contrib.auth.models import User
8+
from users.models import User
99
from django.contrib.postgres.fields import ArrayField
1010
from django.core import serializers
1111
from django.core.validators import MinValueValidator
1212
from django.db import models
1313
from django.urls import reverse
1414
from django.utils import timezone
1515
from netbox.models import PrimaryModel
16-
from netbox.models.features import ChangeLoggingMixin, ExportTemplatesMixin, WebhooksMixin
16+
from netbox.models.features import ChangeLoggingMixin, ExportTemplatesMixin, EventRulesMixin
1717
from utilities.querysets import RestrictedQuerySet
1818

1919
from .choices import LogLevelChoices, ScriptExecutionStatusChoices
@@ -45,9 +45,6 @@ class Meta:
4545
def __str__(self):
4646
return str(self.pk)
4747

48-
def get_absolute_url(self):
49-
return reverse("plugins:netbox_script_manager:script_log_line", args=[self.pk])
50-
5148
def get_level_color(self):
5249
return LogLevelChoices.colors.get(self.level)
5350

@@ -74,7 +71,7 @@ def get_absolute_url(self):
7471
return reverse("plugins:netbox_script_manager:scriptartifact_download", args=[self.pk])
7572

7673

77-
class ScriptExecution(ExportTemplatesMixin, WebhooksMixin, ChangeLoggingMixin, models.Model):
74+
class ScriptExecution(ExportTemplatesMixin, EventRulesMixin, ChangeLoggingMixin, models.Model):
7875
script_instance = models.ForeignKey(
7976
to="ScriptInstance",
8077
on_delete=models.CASCADE,
@@ -153,7 +150,7 @@ def delete(self, *args, **kwargs):
153150
if task:
154151
task.cancel()
155152

156-
def serialize_object(obj, resolve_tags=True, extra=None):
153+
def serialize_object(obj, resolve_tags=True, extra=None, exclude=None):
157154
"""
158155
While the netbox serialize_object claims to support excluding fields, it doesn't in reality.
159156
"""

netbox_script_manager/navigation.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from extras.plugins import PluginMenuButton, PluginMenuItem
2-
from utilities.choices import ButtonColorChoices
1+
from netbox.plugins import PluginMenuButton, PluginMenuItem
32

43
menu_items = (
54
PluginMenuItem(
@@ -11,7 +10,6 @@
1110
link="plugins:netbox_script_manager:scriptinstance_load",
1211
title="Load Scripts",
1312
icon_class="mdi mdi-refresh",
14-
color=ButtonColorChoices.CYAN,
1513
permissions=["netbox_script_manager.add_scriptinstance"],
1614
),
1715
),

netbox_script_manager/project-static/src/App.svelte

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
1717
// Mapping of log level to bootstrap color
1818
let levelColors = {
19-
debug: "bg-gray",
20-
info: "bg-cyan",
21-
success: "bg-green",
22-
warning: "bg-yellow",
23-
failure: "bg-red",
19+
debug: "text-bg-gray",
20+
info: "text.bg-cyan",
21+
success: "text-bg-green",
22+
warning: "text-bg-yellow",
23+
failure: "text-bg-red",
2424
};
2525
2626
// Column definitions
@@ -44,7 +44,7 @@
4444
renderValue: (v) => {
4545
let bgColor = levelColors[v.level.toLowerCase()];
4646
return `<span class="badge ${bgColor}">${capitalize(
47-
v.level
47+
v.level,
4848
)}</span>`;
4949
},
5050
parseHTML: true,
@@ -148,4 +148,5 @@
148148
{rows}
149149
bind:filterSelections={selection}
150150
classNameTable={["table table-hover"]}
151+
classNameInput={["ts-control"]}
151152
/>

netbox_script_manager/scripts.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
from django.db import transaction
1111
from django.forms.fields import BooleanField
1212
from django.utils.functional import classproperty
13-
from extras.context_managers import change_logging
13+
from netbox.context_managers import event_tracking
1414
from extras.scripts import ScriptVariable
15-
from extras.signals import clear_webhooks
15+
from core.signals import clear_events
1616
from utilities.exceptions import AbortScript, AbortTransaction
1717

1818
from .choices import LogLevelChoices, ScriptExecutionStatusChoices
@@ -263,7 +263,7 @@ def _run_script():
263263
raise AbortTransaction()
264264
except AbortTransaction:
265265
script.log_info("Database changes have been reverted automatically.")
266-
clear_webhooks.send(request)
266+
clear_events.send(request)
267267

268268
script_execution.data["output"] = str(output)
269269
script_execution.terminate()
@@ -280,14 +280,14 @@ def _run_script():
280280
script_execution.data["output"] = str(output)
281281

282282
script_execution.terminate(status=ScriptExecutionStatusChoices.STATUS_ERRORED)
283-
clear_webhooks.send(request)
283+
clear_events.send(request)
284284

285285
logger.info(f"Script completed in {script_execution.duration}")
286286

287287
# Execute the script. If commit is True, wrap it with the change_logging context manager to ensure we process
288288
# change logging, webhooks, etc.
289289
if commit:
290-
with change_logging(request):
290+
with event_tracking(request):
291291
_run_script()
292292
else:
293293
_run_script()
@@ -307,7 +307,7 @@ def _run_script():
307307
"output": None,
308308
}
309309

310-
with change_logging(request):
310+
with event_tracking(request):
311311
next_execution = ScriptExecution(
312312
script_instance=script_execution.script_instance,
313313
task_id=uuid.uuid4(),

netbox_script_manager/static/netbox_script_manager/main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

netbox_script_manager/tables.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class ScriptInstanceTable(NetBoxTable):
1717
last_execution = tables.TemplateColumn(
1818
template_code="""
1919
{% if value %}
20-
{{ value.created }}
20+
{{ value.created|isodatetime }}
2121
{% else %}
2222
<span class="text-muted">Never</span>
2323
{% endif %}

0 commit comments

Comments
 (0)