1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Enable scheduling_enabled parameter for reports

This commit is contained in:
jeremystretch
2023-04-17 13:12:14 -04:00
committed by Jeremy Stretch
parent 197c6a1cbf
commit b167153186
8 changed files with 43 additions and 18 deletions

View File

@ -91,6 +91,10 @@ As you can see, reports are completely customizable. Validation logic can be as
A human-friendly description of what your report does.
### `scheduling_enabled`
By default, a report can be scheduled for execution at a later time. Setting `scheduling_enabled` to False disables this ability: Only immediate execution will be possible. (This also disables the ability to set a recurring execution interval.)
### `job_timeout`
Set the maximum allowed runtime for the report. If not set, `RQ_DEFAULT_TIMEOUT` will be used.

View File

@ -57,6 +57,7 @@ Two new webhook trigger events have been introduced: `job_start` and `job_end`.
* [#10729](https://github.com/netbox-community/netbox/issues/10729) - Add date & time custom field type
* [#11029](https://github.com/netbox-community/netbox/issues/11029) - Enable change logging for cable terminations
* [#11254](https://github.com/netbox-community/netbox/issues/11254) - Introduce the `X-Request-ID` HTTP header to annotate the unique ID of each request for change logging
* [#11255](https://github.com/netbox-community/netbox/issues/11255) - Introduce the `scheduling_enabled` settings for reports & scripts
* [#11291](https://github.com/netbox-community/netbox/issues/11291) - Optimized GraphQL API request handling
* [#11440](https://github.com/netbox-community/netbox/issues/11440) - Add an `enabled` field for device type interfaces
* [#11494](https://github.com/netbox-community/netbox/issues/11494) - Enable filtering objects by create/update request IDs

View File

@ -443,6 +443,16 @@ class ReportInputSerializer(serializers.Serializer):
schedule_at = serializers.DateTimeField(required=False, allow_null=True)
interval = serializers.IntegerField(required=False, allow_null=True)
def validate_schedule_at(self, value):
if value and not self.context['report'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this report.")
return value
def validate_interval(self, value):
if value and not self.context['report'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this report.")
return value
#
# Scripts

View File

@ -244,8 +244,12 @@ class ReportViewSet(ViewSet):
raise RQWorkerNotRunningException()
# Retrieve and run the Report. This will create a new Job.
module, report = self._get_report(pk)
input_serializer = serializers.ReportInputSerializer(data=request.data)
module, report_cls = self._get_report(pk)
report = report_cls()
input_serializer = serializers.ReportInputSerializer(
data=request.data,
context={'report': report}
)
if input_serializer.is_valid():
report.result = Job.enqueue(

View File

@ -25,20 +25,25 @@ class ReportForm(BootstrapMixin, forms.Form):
help_text=_("Interval at which this report is re-run (in minutes)")
)
def clean(self):
scheduled_time = self.cleaned_data['schedule_at']
if scheduled_time and scheduled_time < local_now():
raise forms.ValidationError(_('Scheduled time must be in the future.'))
# When interval is used without schedule at, raise an exception
if self.cleaned_data['interval'] and not scheduled_time:
self.cleaned_data['schedule_at'] = local_now()
return self.cleaned_data
def __init__(self, *args, **kwargs):
def __init__(self, *args, scheduling_enabled=True, **kwargs):
super().__init__(*args, **kwargs)
# Annotate the current system time for reference
now = local_now().strftime('%Y-%m-%d %H:%M:%S')
self.fields['schedule_at'].help_text += f' (current time: <strong>{now}</strong>)'
# Remove scheduling fields if scheduling is disabled
if not scheduling_enabled:
self.fields.pop('schedule_at')
self.fields.pop('interval')
def clean(self):
scheduled_time = self.cleaned_data.get('schedule_at')
if scheduled_time and scheduled_time < local_now():
raise forms.ValidationError(_('Scheduled time must be in the future.'))
# When interval is used without schedule at, schedule for the current time
if self.cleaned_data.get('interval') and not scheduled_time:
self.cleaned_data['schedule_at'] = local_now()
return self.cleaned_data

View File

@ -44,12 +44,12 @@ class ScriptForm(BootstrapMixin, forms.Form):
self.fields.pop('_interval')
def clean(self):
scheduled_time = self.cleaned_data['_schedule_at']
scheduled_time = self.cleaned_data.get('_schedule_at')
if scheduled_time and scheduled_time < local_now():
raise forms.ValidationError(_('Scheduled time must be in the future.'))
# When interval is used without schedule at, schedule for the current time
if self.cleaned_data['_interval'] and not scheduled_time:
if self.cleaned_data.get('_interval') and not scheduled_time:
self.cleaned_data['_schedule_at'] = local_now()
return self.cleaned_data

View File

@ -83,6 +83,7 @@ class Report(object):
}
"""
description = None
scheduling_enabled = True
job_timeout = None
def __init__(self):

View File

@ -876,7 +876,7 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
return render(request, 'extras/report.html', {
'module': module,
'report': report,
'form': ReportForm(),
'form': ReportForm(scheduling_enabled=report.scheduling_enabled),
})
def post(self, request, module, name):
@ -885,7 +885,7 @@ class ReportView(ContentTypePermissionRequiredMixin, View):
module = get_object_or_404(ReportModule.objects.restrict(request.user), file_path__startswith=module)
report = module.reports[name]()
form = ReportForm(request.POST)
form = ReportForm(request.POST, scheduling_enabled=report.scheduling_enabled)
if form.is_valid():