Add add/delete views for reports & scripts

This commit is contained in:
jeremystretch 2023-03-23 17:01:12 -04:00
parent 1daac5f781
commit b2bba7fc40
11 changed files with 126 additions and 37 deletions

View File

@ -3,12 +3,14 @@ import copy
from django import forms
from core.models import *
from extras.forms.mixins import SyncedDataMixin
from netbox.forms import NetBoxModelForm
from netbox.registry import registry
from utilities.forms import BootstrapMixin, CommentField, get_field_value
from utilities.forms import CommentField, get_field_value
__all__ = (
'DataSourceForm',
'ManagedFileForm',
)
@ -73,3 +75,26 @@ class DataSourceForm(NetBoxModelForm):
self.instance.parameters = parameters
return super().save(*args, **kwargs)
class ManagedFileForm(SyncedDataMixin, NetBoxModelForm):
upload_file = forms.FileField(
required=False
)
fieldsets = (
('File Upload', ('upload_file',)),
('Data Source', ('data_source', 'data_file')),
)
class Meta:
model = ManagedFile
fields = ('data_source', 'data_file')
def clean(self):
super().clean()
if self.cleaned_data.get('upload_file') and self.cleaned_data.get('data_file'):
raise forms.ValidationError("Cannot upload a file and sync from an existing file")
return self.cleaned_data

View File

@ -315,3 +315,14 @@ class DataFile(models.Model):
self.data = f.read()
return is_modified
def write_to_disk(self, path, overwrite=False):
"""
Write the object's data to disk at the specified path
"""
# Check whether file already exists
if os.path.isfile(path) and not overwrite:
raise FileExistsError()
with open(path, 'wb+') as new_file:
new_file.write(self.data)

View File

@ -71,3 +71,14 @@ class ManagedFile(SyncedDataMixin, models.Model):
'scripts': settings.SCRIPTS_ROOT,
'reports': settings.REPORTS_ROOT,
}[self.file_root]
def sync_data(self):
if self.data_file:
self.file_path = self.data_path
self.data_file.write_to_disk(self.full_path, overwrite=True)
def delete(self, *args, **kwargs):
# Delete file from disk
os.remove(self.full_path)
return super().delete(*args, **kwargs)

View File

@ -21,9 +21,6 @@ urlpatterns = (
# Managed files
path('files/', views.ManagedFileListView.as_view(), name='managedfile_list'),
# path('files/add/', views.ManagedFileEditView.as_view(), name='managedfile_add'),
# path('files/edit/', views.ManagedFileBulkEditView.as_view(), name='managedfile_bulk_edit'),
# path('files/delete/', views.ManagedFileBulkDeleteView.as_view(), name='managedfile_bulk_delete'),
path('files/<int:pk>/', include(get_model_urls('core', 'managedfile'))),
)

View File

@ -128,35 +128,9 @@ class DataFileBulkDeleteView(generic.BulkDeleteView):
class ManagedFileListView(generic.ObjectListView):
queryset = ManagedFile.objects.all()
# filterset = filtersets.ManagedFileFilterSet
# filterset_form = forms.ManagedFileFilterForm
table = tables.ManagedFileTable
@register_model_view(ManagedFile)
class ManagedFileView(generic.ObjectView):
queryset = ManagedFile.objects.all()
# @register_model_view(ManagedFile, 'edit')
# class ManagedFileEditView(generic.ObjectEditView):
# queryset = ManagedFile.objects.all()
# form = forms.ManagedFileForm
@register_model_view(ManagedFile, 'delete')
class ManagedFileDeleteView(generic.ObjectDeleteView):
queryset = ManagedFile.objects.all()
# class ManagedFileBulkEditView(generic.BulkEditView):
# queryset = ManagedFile.objects.all()
# # filterset = filtersets.ManagedFileFilterSet
# table = tables.ManagedFileTable
# form = forms.ManagedFileBulkEditForm
# class ManagedFileBulkDeleteView(generic.BulkDeleteView):
# queryset = ManagedFile.objects.all()
# # filterset = filtersets.ManagedFileFilterSet
# table = tables.ManagedFileTable

View File

@ -17,6 +17,10 @@ WEBHOOK_EVENT_TYPES = {
EVENT_JOB_END: 'job_ended',
}
# Managed files
REPORTS_ROOT_NAME = 'reports'
SCRIPTS_ROOT_NAME = 'scripts'
# Dashboard
DEFAULT_DASHBOARD = [
{

View File

@ -836,7 +836,7 @@ class Script(JobResultsMixin, WebhooksMixin, models.Model):
managed = False
class ScriptModuleManager(models.Manager):
class ScriptModuleManager(models.Manager.from_queryset(RestrictedQuerySet)):
def get_queryset(self):
return super().get_queryset().filter(file_root='scripts')
@ -851,6 +851,10 @@ class ScriptModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.file_root = SCRIPTS_ROOT_NAME
return super().save(*args, **kwargs)
#
# Reports
@ -864,7 +868,7 @@ class Report(JobResultsMixin, WebhooksMixin, models.Model):
managed = False
class ReportModuleManager(models.Manager):
class ReportModuleManager(models.Manager.from_queryset(RestrictedQuerySet)):
def get_queryset(self):
return super().get_queryset().filter(file_root='reports')
@ -878,3 +882,7 @@ class ReportModule(JobResultsMixin, WebhooksMixin, PythonModuleMixin, ManagedFil
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.file_root = REPORTS_ROOT_NAME
return super().save(*args, **kwargs)

View File

@ -96,17 +96,21 @@ urlpatterns = [
path('reports/', views.ReportListView.as_view(), name='report_list'),
path('reports/results/<int:job_result_pk>/', views.ReportResultView.as_view(), name='report_result'),
re_path(r'^reports/(?P<module>.([^.]+)).(?P<name>.(.+))/', views.ReportView.as_view(), name='report'),
path('reports/add/', views.ScriptModuleCreateView.as_view(), name='reportmodule_add'),
path('reports/<int:pk>/', include(get_model_urls('extras', 'reportmodule'))),
# Scripts
path('scripts/', views.ScriptListView.as_view(), name='script_list'),
path('scripts/results/<int:job_result_pk>/', views.ScriptResultView.as_view(), name='script_result'),
re_path(r'^scripts/(?P<module>.([^.]+)).(?P<name>.(.+))/', views.ScriptView.as_view(), name='script'),
path('scripts/add/', views.ScriptModuleCreateView.as_view(), name='scriptmodule_add'),
path('scripts/<int:pk>/', include(get_model_urls('extras', 'scriptmodule'))),
# Job results
path('job-results/', views.JobResultListView.as_view(), name='jobresult_list'),
path('job-results/delete/', views.JobResultBulkDeleteView.as_view(), name='jobresult_bulk_delete'),
path('job-results/<int:pk>/delete/', views.JobResultDeleteView.as_view(), name='jobresult_delete'),
# Scripts
path('scripts/', views.ScriptListView.as_view(), name='script_list'),
path('scripts/results/<int:job_result_pk>/', views.ScriptResultView.as_view(), name='script_result'),
re_path(r'^scripts/(?P<module>.([^.]+)).(?P<name>.(.+))/', views.ScriptView.as_view(), name='script'),
# Markdown
path('render/markdown/', views.RenderMarkdownView.as_view(), name="render_markdown")
]

View File

@ -7,6 +7,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.generic import View
from core.forms import ManagedFileForm
from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm
from extras.dashboard.utils import get_widget_class
from netbox.views import generic
@ -18,6 +19,7 @@ from utilities.utils import copy_safe_request, count_related, get_viewname, norm
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
from . import filtersets, forms, tables
from .choices import JobResultStatusChoices
from .constants import SCRIPTS_ROOT_NAME, REPORTS_ROOT_NAME
from .forms.reports import ReportForm
from .models import *
from .reports import get_report, get_reports, run_report
@ -790,6 +792,21 @@ class DashboardWidgetDeleteView(LoginRequiredMixin, View):
# Reports
#
@register_model_view(ReportModule, 'edit')
class ReportModuleCreateView(generic.ObjectEditView):
queryset = ReportModule.objects.all()
form = ManagedFileForm
def alter_object(self, obj, *args, **kwargs):
obj.file_root = REPORTS_ROOT_NAME
return obj
@register_model_view(ReportModule, 'delete')
class ReportModuleDeleteView(generic.ObjectDeleteView):
queryset = ReportModule.objects.all()
class ReportListView(ContentTypePermissionRequiredMixin, View):
"""
Retrieve all of the available reports from disk and the recorded JobResult (if any) for each.
@ -819,6 +836,7 @@ class ReportListView(ContentTypePermissionRequiredMixin, View):
ret.append((module, module_reports))
return render(request, 'extras/report_list.html', {
'model': ReportModule,
'reports': ret,
})
@ -924,6 +942,21 @@ class ReportResultView(ContentTypePermissionRequiredMixin, View):
# Scripts
#
@register_model_view(ScriptModule, 'edit')
class ScriptModuleCreateView(generic.ObjectEditView):
queryset = ScriptModule.objects.all()
form = ManagedFileForm
def alter_object(self, obj, *args, **kwargs):
obj.file_root = SCRIPTS_ROOT_NAME
return obj
@register_model_view(ScriptModule, 'delete')
class ScriptModuleDeleteView(generic.ObjectDeleteView):
queryset = ScriptModule.objects.all()
class GetScriptMixin:
def _get_script(self, name, module=None):
if module is None:
@ -957,6 +990,7 @@ class ScriptListView(ContentTypePermissionRequiredMixin, View):
script.result = results.get(script.full_name)
return render(request, 'extras/script_list.html', {
'model': ScriptModule,
'scripts': scripts,
})

View File

@ -1,5 +1,7 @@
{% extends 'base/layout.html' %}
{% load buttons %}
{% load helpers %}
{% load perms %}
{% block title %}Reports{% endblock %}
@ -11,6 +13,15 @@
</ul>
{% endblock tabs %}
{% block controls %}
<div class="controls">
<div class="control-group">
{% block extra_controls %}{% endblock %}
{% add_button model %}
</div>
</div>
{% endblock controls %}
{% block content-wrapper %}
<div class="tab-content">
{% if reports %}

View File

@ -1,8 +1,18 @@
{% extends 'base/layout.html' %}
{% load buttons %}
{% load helpers %}
{% block title %}Scripts{% endblock %}
{% block controls %}
<div class="controls">
<div class="control-group">
{% block extra_controls %}{% endblock %}
{% add_button model %}
</div>
</div>
{% endblock controls %}
{% block tabs %}
<ul class="nav nav-tabs px-3">
<li class="nav-item" role="presentation">