Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/customization/custom-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ An IPv4 or IPv6 network with a mask. Returns a `netaddr.IPNetwork` object. Two a
* `min_prefix_length` - Minimum length of the mask
* `max_prefix_length` - Maximum length of the mask

### DateVar

A calendar date. Returns a `datetime.date` object.

### DateTimeVar

A complete date & time. Returns a `datetime.datetime` object.

## Running Custom Scripts

!!! note
Expand Down
25 changes: 25 additions & 0 deletions netbox/extras/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
from utilities.exceptions import AbortScript, AbortTransaction
from utilities.forms import add_blank_choice
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.widgets import DatePicker, DateTimePicker
from .context_managers import event_tracking
from .forms import ScriptForm

__all__ = (
'BaseScript',
'BooleanVar',
'ChoiceVar',
'DateVar',
'DateTimeVar',
'FileVar',
'IntegerVar',
'IPAddressVar',
Expand Down Expand Up @@ -172,6 +175,28 @@ def __init__(self, choices, *args, **kwargs):
self.field_attrs['choices'] = add_blank_choice(choices)


class DateVar(ScriptVariable):
"""
A date.
"""
form_field = forms.DateField

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_field.widget = DatePicker()


class DateTimeVar(ScriptVariable):
"""
A date and a time.
"""
form_field = forms.DateTimeField

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_field.widget = DateTimePicker()


class MultiChoiceVar(ScriptVariable):
"""
Like ChoiceVar, but allows for the selection of multiple choices.
Expand Down
45 changes: 45 additions & 0 deletions netbox/extras/tests/test_scripts.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tempfile
from datetime import date, datetime, timezone

from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
Expand Down Expand Up @@ -322,3 +323,47 @@ class TestScript(Script):
form = TestScript().as_form(data, None)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], IPNetwork(data['var1']))

def test_datevar(self):

class TestScript(Script):

var1 = DateVar()
var2 = DateVar(required=False)

# Test date validation
data = {'var1': 'not a date'}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors)

# Validate valid data
input_date = date(2024, 4, 1)
data = {'var1': input_date}
form = TestScript().as_form(data, None)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], input_date)
# Validate required=False works for this Var type
self.assertEqual(form.cleaned_data['var2'], None)

def test_datetimevar(self):

class TestScript(Script):

var1 = DateTimeVar()
var2 = DateTimeVar(required=False)

# Test datetime validation
data = {'var1': 'not a datetime'}
form = TestScript().as_form(data, None)
self.assertFalse(form.is_valid())
self.assertIn('var1', form.errors)

# Validate valid data
input_datetime = datetime(2024, 4, 1, 8, 0, 0, 0, timezone.utc)
data = {'var1': input_datetime}
form = TestScript().as_form(data, None)
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['var1'], input_datetime)
# Validate required=False works for this Var type
self.assertEqual(form.cleaned_data['var2'], None)