Skip to content

Commit 0b120e6

Browse files
Merge pull request #17346 from netbox-community/develop
Release v4.0.11
2 parents e93e9ac + e174a8a commit 0b120e6

File tree

49 files changed

+4454
-4338
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4454
-4338
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ body:
2626
attributes:
2727
label: NetBox Version
2828
description: What version of NetBox are you currently running?
29-
placeholder: v4.0.10
29+
placeholder: v4.0.11
3030
validations:
3131
required: true
3232
- type: dropdown

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ body:
1414
attributes:
1515
label: NetBox version
1616
description: What version of NetBox are you currently running?
17-
placeholder: v4.0.10
17+
placeholder: v4.0.11
1818
validations:
1919
required: true
2020
- type: dropdown

docs/release-notes/version-4.0.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# NetBox v4.0
22

3+
## v4.0.11 (2024-09-03)
4+
5+
### Bug Fixes
6+
7+
* [#17310](https://github.com/netbox-community/netbox/issues/17310) - Enforce restricted queryset for related objects in GraphQL API requests
8+
* [#17321](https://github.com/netbox-community/netbox/issues/17321) - Ensure the job is attributed to the specified user when using the `runscript` management command
9+
* [#17323](https://github.com/netbox-community/netbox/issues/17323) - Associate job with script object when executed using the `runscript` management command
10+
* [#17337](https://github.com/netbox-community/netbox/issues/17337) - Fix ordering of virtual device contexts by device name
11+
* [#17341](https://github.com/netbox-community/netbox/issues/17341) - Avoid `NoReverseMatch` exceptions with specific dashboard widget configurations
12+
313
## v4.0.10 (2024-08-29)
414

515
### Enhancements

netbox/circuits/tests/test_api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
9696
bulk_update_data = {
9797
'status': 'planned',
9898
}
99+
user_permissions = ('circuits.view_provider', 'circuits.view_circuittype')
99100

100101
@classmethod
101102
def setUpTestData(cls):
@@ -150,6 +151,7 @@ def setUpTestData(cls):
150151
class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
151152
model = CircuitTermination
152153
brief_fields = ['_occupied', 'cable', 'circuit', 'description', 'display', 'id', 'term_side', 'url']
154+
user_permissions = ('circuits.view_circuit', )
153155

154156
@classmethod
155157
def setUpTestData(cls):
@@ -209,6 +211,7 @@ def setUpTestData(cls):
209211
class ProviderAccountTest(APIViewTestCases.APIViewTestCase):
210212
model = ProviderAccount
211213
brief_fields = ['account', 'description', 'display', 'id', 'name', 'url']
214+
user_permissions = ('circuits.view_provider', )
212215

213216
@classmethod
214217
def setUpTestData(cls):
@@ -252,6 +255,7 @@ def setUpTestData(cls):
252255
class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
253256
model = ProviderNetwork
254257
brief_fields = ['description', 'display', 'id', 'name', 'url']
258+
user_permissions = ('circuits.view_provider', )
255259

256260
@classmethod
257261
def setUpTestData(cls):

netbox/core/tests/test_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class DataFileTest(
5757
):
5858
model = DataFile
5959
brief_fields = ['display', 'id', 'path', 'url']
60+
user_permissions = ('core.view_datasource', )
6061

6162
@classmethod
6263
def setUpTestData(cls):

netbox/dcim/tables/devices.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable):
10311031
)
10321032
device = tables.TemplateColumn(
10331033
verbose_name=_('Device'),
1034-
order_by=('_name',),
1034+
order_by=('device___name',),
10351035
template_code=DEVICE_LINK,
10361036
linkify=True
10371037
)

netbox/dcim/tests/test_api.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
195195
bulk_update_data = {
196196
'description': 'New description',
197197
}
198+
user_permissions = ('dcim.view_site', )
198199

199200
@classmethod
200201
def setUpTestData(cls):
@@ -280,6 +281,7 @@ class RackTest(APIViewTestCases.APIViewTestCase):
280281
bulk_update_data = {
281282
'status': 'planned',
282283
}
284+
user_permissions = ('dcim.view_site', )
283285

284286
@classmethod
285287
def setUpTestData(cls):
@@ -368,6 +370,7 @@ class RackReservationTest(APIViewTestCases.APIViewTestCase):
368370
bulk_update_data = {
369371
'description': 'New description',
370372
}
373+
user_permissions = ('dcim.view_rack', 'users.view_user')
371374

372375
@classmethod
373376
def setUpTestData(cls):
@@ -447,6 +450,7 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
447450
bulk_update_data = {
448451
'part_number': 'ABC123',
449452
}
453+
user_permissions = ('dcim.view_manufacturer', )
450454

451455
@classmethod
452456
def setUpTestData(cls):
@@ -492,6 +496,7 @@ class ModuleTypeTest(APIViewTestCases.APIViewTestCase):
492496
bulk_update_data = {
493497
'part_number': 'ABC123',
494498
}
499+
user_permissions = ('dcim.view_manufacturer', )
495500

496501
@classmethod
497502
def setUpTestData(cls):
@@ -663,6 +668,7 @@ class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase):
663668
bulk_update_data = {
664669
'description': 'New description',
665670
}
671+
user_permissions = ('dcim.view_devicetype', )
666672

667673
@classmethod
668674
def setUpTestData(cls):
@@ -768,6 +774,7 @@ class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase):
768774
bulk_update_data = {
769775
'description': 'New description',
770776
}
777+
user_permissions = ('dcim.view_rearporttemplate', )
771778

772779
@classmethod
773780
def setUpTestData(cls):
@@ -905,6 +912,7 @@ class ModuleBayTemplateTest(APIViewTestCases.APIViewTestCase):
905912
bulk_update_data = {
906913
'description': 'New description',
907914
}
915+
user_permissions = ('dcim.view_devicetype', )
908916

909917
@classmethod
910918
def setUpTestData(cls):
@@ -945,6 +953,7 @@ class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase):
945953
bulk_update_data = {
946954
'description': 'New description',
947955
}
956+
user_permissions = ('dcim.view_devicetype', )
948957

949958
@classmethod
950959
def setUpTestData(cls):
@@ -985,6 +994,7 @@ class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase):
985994
bulk_update_data = {
986995
'description': 'New description',
987996
}
997+
user_permissions = ('dcim.view_devicetype', 'dcim.view_manufacturer',)
988998

989999
@classmethod
9901000
def setUpTestData(cls):
@@ -1103,6 +1113,10 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
11031113
bulk_update_data = {
11041114
'status': 'failed',
11051115
}
1116+
user_permissions = (
1117+
'dcim.view_site', 'dcim.view_rack', 'dcim.view_location', 'dcim.view_devicerole', 'dcim.view_devicetype',
1118+
'extras.view_configtemplate',
1119+
)
11061120

11071121
@classmethod
11081122
def setUpTestData(cls):
@@ -1293,6 +1307,7 @@ class ModuleTest(APIViewTestCases.APIViewTestCase):
12931307
bulk_update_data = {
12941308
'serial': '1234ABCD',
12951309
}
1310+
user_permissions = ('dcim.view_modulebay', 'dcim.view_moduletype', 'dcim.view_device')
12961311

12971312
@classmethod
12981313
def setUpTestData(cls):
@@ -1358,6 +1373,7 @@ class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
13581373
'description': 'New description',
13591374
}
13601375
peer_termination_type = ConsoleServerPort
1376+
user_permissions = ('dcim.view_device', )
13611377

13621378
@classmethod
13631379
def setUpTestData(cls):
@@ -1400,6 +1416,7 @@ class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIView
14001416
'description': 'New description',
14011417
}
14021418
peer_termination_type = ConsolePort
1419+
user_permissions = ('dcim.view_device', )
14031420

14041421
@classmethod
14051422
def setUpTestData(cls):
@@ -1442,6 +1459,7 @@ class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
14421459
'description': 'New description',
14431460
}
14441461
peer_termination_type = PowerOutlet
1462+
user_permissions = ('dcim.view_device', )
14451463

14461464
@classmethod
14471465
def setUpTestData(cls):
@@ -1481,6 +1499,7 @@ class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
14811499
'description': 'New description',
14821500
}
14831501
peer_termination_type = PowerPort
1502+
user_permissions = ('dcim.view_device', )
14841503

14851504
@classmethod
14861505
def setUpTestData(cls):
@@ -1529,6 +1548,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
15291548
'description': 'New description',
15301549
}
15311550
peer_termination_type = Interface
1551+
user_permissions = ('dcim.view_device', )
15321552

15331553
@classmethod
15341554
def setUpTestData(cls):
@@ -1663,6 +1683,7 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase):
16631683
'description': 'New description',
16641684
}
16651685
peer_termination_type = Interface
1686+
user_permissions = ('dcim.view_device', 'dcim.view_rearport')
16661687

16671688
@classmethod
16681689
def setUpTestData(cls):
@@ -1721,6 +1742,7 @@ class RearPortTest(APIViewTestCases.APIViewTestCase):
17211742
'description': 'New description',
17221743
}
17231744
peer_termination_type = Interface
1745+
user_permissions = ('dcim.view_device', )
17241746

17251747
@classmethod
17261748
def setUpTestData(cls):
@@ -1762,6 +1784,7 @@ class ModuleBayTest(APIViewTestCases.APIViewTestCase):
17621784
bulk_update_data = {
17631785
'description': 'New description',
17641786
}
1787+
user_permissions = ('dcim.view_device', )
17651788

17661789
@classmethod
17671790
def setUpTestData(cls):
@@ -1801,6 +1824,7 @@ class DeviceBayTest(APIViewTestCases.APIViewTestCase):
18011824
bulk_update_data = {
18021825
'description': 'New description',
18031826
}
1827+
user_permissions = ('dcim.view_device', )
18041828

18051829
@classmethod
18061830
def setUpTestData(cls):
@@ -1864,6 +1888,7 @@ class InventoryItemTest(APIViewTestCases.APIViewTestCase):
18641888
bulk_update_data = {
18651889
'description': 'New description',
18661890
}
1891+
user_permissions = ('dcim.view_device', 'dcim.view_manufacturer')
18671892

18681893
@classmethod
18691894
def setUpTestData(cls):
@@ -2160,6 +2185,7 @@ def setUpTestData(cls):
21602185
class PowerPanelTest(APIViewTestCases.APIViewTestCase):
21612186
model = PowerPanel
21622187
brief_fields = ['description', 'display', 'id', 'name', 'powerfeed_count', 'url']
2188+
user_permissions = ('dcim.view_site', )
21632189

21642190
@classmethod
21652191
def setUpTestData(cls):
@@ -2212,6 +2238,7 @@ class PowerFeedTest(APIViewTestCases.APIViewTestCase):
22122238
bulk_update_data = {
22132239
'status': 'planned',
22142240
}
2241+
user_permissions = ('dcim.view_powerpanel', )
22152242

22162243
@classmethod
22172244
def setUpTestData(cls):

netbox/extras/dashboard/widgets.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,13 @@ def render(self, request):
183183
for model in get_models_from_content_types(self.config['models']):
184184
permission = get_permission_for_model(model, 'view')
185185
if request.user.has_perm(permission):
186-
url = reverse(get_viewname(model, 'list'))
186+
try:
187+
url = reverse(get_viewname(model, 'list'))
188+
except NoReverseMatch:
189+
url = None
187190
qs = model.objects.restrict(request.user, 'view')
188191
# Apply any specified filters
189-
if filters := self.config.get('filters'):
192+
if url and (filters := self.config.get('filters')):
190193
params = dict_to_querydict(filters)
191194
filterset = getattr(resolve(url).func.view_class, 'filterset', None)
192195
qs = filterset(params, qs).qs

netbox/extras/management/commands/runscript.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def add_arguments(self, parser):
3434

3535
def handle(self, *args, **options):
3636

37-
def _run_script():
37+
def _run_script(script):
3838
"""
3939
Core script execution task. We capture this within a subfunction to allow for conditionally wrapping it with
4040
the event_tracking context manager (which is bypassed if commit == False).
@@ -85,7 +85,6 @@ def _run_script():
8585

8686
module_name, script_name = script.split('.', 1)
8787
module, script = get_module_and_script(module_name, script_name)
88-
script = script.python_class
8988

9089
# Take user from command line if provided and exists, other
9190
if options['user']:
@@ -102,7 +101,7 @@ def _run_script():
102101
stdouthandler.setLevel(logging.DEBUG)
103102
stdouthandler.setFormatter(formatter)
104103

105-
logger = logging.getLogger(f"netbox.scripts.{script.full_name}")
104+
logger = logging.getLogger(f"netbox.scripts.{script.python_class.full_name}")
106105
logger.addHandler(stdouthandler)
107106

108107
try:
@@ -118,14 +117,14 @@ def _run_script():
118117
raise CommandError(f"Invalid log level: {loglevel}")
119118

120119
# Initialize the script form
121-
script = script()
122-
form = script.as_form(data, None)
120+
script_instance = script.python_class()
121+
form = script_instance.as_form(data, None)
123122

124123
# Create the job
125124
job = Job.objects.create(
126-
object=module,
127-
name=script.class_name,
128-
user=User.objects.filter(is_superuser=True).order_by('pk')[0],
125+
object=script,
126+
name=script_instance.class_name,
127+
user=user,
129128
job_id=uuid.uuid4()
130129
)
131130

@@ -149,7 +148,7 @@ def _run_script():
149148
# Execute the script. If commit is True, wrap it with the event_tracking context manager to ensure we process
150149
# change logging, webhooks, etc.
151150
with event_tracking(request):
152-
_run_script()
151+
_run_script(script_instance)
153152
else:
154153
logger.error('Data is not valid:')
155154
for field, errors in form.errors.get_json_data().items():

netbox/ipam/tests/test_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ class FHRPGroupAssignmentTest(APIViewTestCases.APIViewTestCase):
767767
bulk_update_data = {
768768
'priority': 100,
769769
}
770+
user_permissions = ('ipam.view_fhrpgroup', )
770771

771772
@classmethod
772773
def setUpTestData(cls):

0 commit comments

Comments
 (0)