mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 17:26:10 -06:00
Enable resolving scripts/reports from module class
This commit is contained in:
parent
bfccd6820e
commit
f5830c1cd8
@ -1,5 +1,7 @@
|
||||
import inspect
|
||||
import json
|
||||
import uuid
|
||||
from functools import cached_property
|
||||
from pkgutil import ModuleInfo, get_importer
|
||||
|
||||
from django.conf import settings
|
||||
@ -31,6 +33,7 @@ from netbox.models.features import (
|
||||
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, SyncedDataMixin,
|
||||
TagsMixin, WebhooksMixin,
|
||||
)
|
||||
from ..temp import is_report, is_script
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from utilities.rqworker import get_queue_for_model
|
||||
from utilities.utils import render_jinja2
|
||||
@ -827,6 +830,11 @@ class PythonModuleMixin:
|
||||
ispkg=False
|
||||
)
|
||||
|
||||
def get_module(self):
|
||||
importer, module_name, _ = self.get_module_info()
|
||||
module = importer.find_module(module_name).load_module(module_name)
|
||||
return module
|
||||
|
||||
|
||||
class Script(JobResultsMixin, WebhooksMixin, models.Model):
|
||||
"""
|
||||
@ -862,6 +870,18 @@ class ScriptModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
|
||||
def name(self):
|
||||
return self.file_path
|
||||
|
||||
@cached_property
|
||||
def scripts(self):
|
||||
module = self.get_module()
|
||||
|
||||
scripts = {}
|
||||
for name, cls in inspect.getmembers(module, is_script):
|
||||
# For child objects in submodules use the full import path w/o the root module as the name
|
||||
child_name = cls.full_name.split(".", maxsplit=1)[1]
|
||||
scripts[child_name] = cls
|
||||
|
||||
return scripts
|
||||
|
||||
|
||||
#
|
||||
# Reports
|
||||
@ -896,3 +916,15 @@ class ReportModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('extras:report_list')
|
||||
|
||||
@cached_property
|
||||
def reports(self):
|
||||
module = self.get_module()
|
||||
|
||||
reports = {}
|
||||
for name, cls in inspect.getmembers(module, is_report):
|
||||
# For child objects in submodules use the full import path w/o the root module as the name
|
||||
child_name = cls().full_name.split(".", maxsplit=1)[1]
|
||||
reports[child_name] = cls
|
||||
|
||||
return reports
|
||||
|
@ -7,18 +7,12 @@ from django_rq import job
|
||||
|
||||
from .choices import JobResultStatusChoices, LogLevelChoices
|
||||
from .models import JobResult, ReportModule
|
||||
from .temp import is_report
|
||||
from .utils import get_modules
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def is_report(obj):
|
||||
"""
|
||||
Returns True if the given object is a Report.
|
||||
"""
|
||||
return obj in Report.__subclasses__()
|
||||
|
||||
|
||||
def get_reports():
|
||||
return get_modules(ReportModule.objects.all(), is_report, 'report_order')
|
||||
|
||||
|
@ -22,6 +22,7 @@ from utilities.exceptions import AbortScript, AbortTransaction
|
||||
from utilities.forms import add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
||||
from .context_managers import change_logging
|
||||
from .forms import ScriptForm
|
||||
from .temp import is_script
|
||||
from .utils import get_modules
|
||||
|
||||
__all__ = [
|
||||
@ -423,15 +424,6 @@ class Script(BaseScript):
|
||||
# Functions
|
||||
#
|
||||
|
||||
def is_script(obj):
|
||||
"""
|
||||
Returns True if the object is a Script.
|
||||
"""
|
||||
try:
|
||||
return issubclass(obj, Script) and obj != Script
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
|
||||
def is_variable(obj):
|
||||
"""
|
||||
|
20
netbox/extras/temp.py
Normal file
20
netbox/extras/temp.py
Normal file
@ -0,0 +1,20 @@
|
||||
def is_script(obj):
|
||||
"""
|
||||
Returns True if the object is a Script.
|
||||
"""
|
||||
from .scripts import Script
|
||||
try:
|
||||
return issubclass(obj, Script) and obj != Script
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
|
||||
def is_report(obj):
|
||||
"""
|
||||
Returns True if the given object is a Report.
|
||||
"""
|
||||
from .reports import Report
|
||||
try:
|
||||
return issubclass(obj, Report) and obj != Report
|
||||
except TypeError:
|
||||
return False
|
@ -849,10 +849,8 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
|
||||
return 'extras.view_report'
|
||||
|
||||
def get(self, request, module, name):
|
||||
|
||||
report = get_report(module, name)
|
||||
if report is None:
|
||||
raise Http404
|
||||
module = get_object_or_404(ReportModule.objects.restrict(request.user), file_path=f'{module}.py')
|
||||
report = module.reports[name]()
|
||||
|
||||
report_content_type = ContentType.objects.get(app_label='extras', model='report')
|
||||
report.result = JobResult.objects.filter(
|
||||
@ -1001,7 +999,8 @@ class ScriptView(ContentTypePermissionRequiredMixin, GetScriptMixin, View):
|
||||
return 'extras.view_script'
|
||||
|
||||
def get(self, request, module, name):
|
||||
script = self._get_script(name, module)
|
||||
module = get_object_or_404(ScriptModule.objects.restrict(request.user), file_path=f'{module}.py')
|
||||
script = module.scripts[name]()
|
||||
form = script.as_form(initial=normalize_querydict(request.GET))
|
||||
|
||||
# Look for a pending JobResult (use the latest one by creation timestamp)
|
||||
|
Loading…
Reference in New Issue
Block a user