diff --git a/netbox/extras/models/scripts.py b/netbox/extras/models/scripts.py index e857e59b7fb..7e24b73536c 100644 --- a/netbox/extras/models/scripts.py +++ b/netbox/extras/models/scripts.py @@ -96,6 +96,7 @@ class ScriptModule(PythonModuleMixin, JobsMixin, ManagedFile): Proxy model for script module files. """ objects = ScriptModuleManager() + error = None class Meta: proxy = True @@ -118,6 +119,7 @@ def _get_name(cls): try: module = self.get_module() except Exception as e: + self.error = e logger.debug(f"Failed to load script: {self.python_name} error: {e}") module = None diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 1fa2a30aacd..f7e29512956 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -1040,12 +1040,27 @@ def get(self, request): }) -class ScriptView(generic.ObjectView): +class BaseScriptView(generic.ObjectView): queryset = Script.objects.all() + def _get_script_class(self, script): + """ + Return an instance of the Script's Python class + """ + if script_class := script.python_class: + return script_class() + + +class ScriptView(BaseScriptView): + def get(self, request, **kwargs): script = self.get_object(**kwargs) - script_class = script.python_class() + script_class = self._get_script_class(script) + if not script_class: + return render(request, 'extras/script.html', { + 'script': script, + }) + form = script_class.as_form(initial=normalize_querydict(request.GET)) return render(request, 'extras/script.html', { @@ -1057,11 +1072,16 @@ def get(self, request, **kwargs): def post(self, request, **kwargs): script = self.get_object(**kwargs) - script_class = script.python_class() if not request.user.has_perm('extras.run_script', obj=script): return HttpResponseForbidden() + script_class = self._get_script_class(script) + if not script_class: + return render(request, 'extras/script.html', { + 'script': script, + }) + form = script_class.as_form(request.POST, request.FILES) # Allow execution only if RQ worker process is running @@ -1091,21 +1111,22 @@ def post(self, request, **kwargs): }) -class ScriptSourceView(generic.ObjectView): +class ScriptSourceView(BaseScriptView): queryset = Script.objects.all() def get(self, request, **kwargs): script = self.get_object(**kwargs) + script_class = self._get_script_class(script) return render(request, 'extras/script/source.html', { 'script': script, - 'script_class': script.python_class(), + 'script_class': script_class, 'job_count': script.jobs.count(), 'tab': 'source', }) -class ScriptJobsView(generic.ObjectView): +class ScriptJobsView(BaseScriptView): queryset = Script.objects.all() def get(self, request, **kwargs): diff --git a/netbox/templates/extras/script.html b/netbox/templates/extras/script.html index 8a4f8657962..fe616dc8a40 100644 --- a/netbox/templates/extras/script.html +++ b/netbox/templates/extras/script.html @@ -14,38 +14,43 @@ {% trans "You do not have permission to run scripts" %}. {% endif %} -