mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 12:12:53 -06:00
Merge branch 'develop' into feature
This commit is contained in:
commit
a777850702
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -26,7 +26,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox Version
|
label: NetBox Version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v4.0.10
|
placeholder: v4.0.11
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v4.0.10
|
placeholder: v4.0.11
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
# NetBox v4.0
|
# NetBox v4.0
|
||||||
|
|
||||||
|
## v4.0.11 (2024-09-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#17310](https://github.com/netbox-community/netbox/issues/17310) - Enforce restricted queryset for related objects in GraphQL API requests
|
||||||
|
* [#17321](https://github.com/netbox-community/netbox/issues/17321) - Ensure the job is attributed to the specified user when using the `runscript` management command
|
||||||
|
* [#17323](https://github.com/netbox-community/netbox/issues/17323) - Associate job with script object when executed using the `runscript` management command
|
||||||
|
* [#17337](https://github.com/netbox-community/netbox/issues/17337) - Fix ordering of virtual device contexts by device name
|
||||||
|
* [#17341](https://github.com/netbox-community/netbox/issues/17341) - Avoid `NoReverseMatch` exceptions with specific dashboard widget configurations
|
||||||
|
|
||||||
## v4.0.10 (2024-08-29)
|
## v4.0.10 (2024-08-29)
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
@ -96,6 +96,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'status': 'planned',
|
'status': 'planned',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('circuits.view_provider', 'circuits.view_circuittype')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -150,6 +151,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
|
class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
brief_fields = ['_occupied', 'cable', 'circuit', 'description', 'display', 'id', 'term_side', 'url']
|
brief_fields = ['_occupied', 'cable', 'circuit', 'description', 'display', 'id', 'term_side', 'url']
|
||||||
|
user_permissions = ('circuits.view_circuit', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -241,6 +243,7 @@ class CircuitGroupTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class ProviderAccountTest(APIViewTestCases.APIViewTestCase):
|
class ProviderAccountTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = ProviderAccount
|
model = ProviderAccount
|
||||||
brief_fields = ['account', 'description', 'display', 'id', 'name', 'url']
|
brief_fields = ['account', 'description', 'display', 'id', 'name', 'url']
|
||||||
|
user_permissions = ('circuits.view_provider',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -287,6 +290,7 @@ class CircuitGroupAssignmentTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'priority': CircuitPriorityChoices.PRIORITY_INACTIVE,
|
'priority': CircuitPriorityChoices.PRIORITY_INACTIVE,
|
||||||
}
|
}
|
||||||
|
user_permissions = ('circuits.view_circuit', 'circuits.view_circuitgroup')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -355,6 +359,7 @@ class CircuitGroupAssignmentTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
|
class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = ProviderNetwork
|
model = ProviderNetwork
|
||||||
brief_fields = ['description', 'display', 'id', 'name', 'url']
|
brief_fields = ['description', 'display', 'id', 'name', 'url']
|
||||||
|
user_permissions = ('circuits.view_provider', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -57,6 +57,7 @@ class DataFileTest(
|
|||||||
):
|
):
|
||||||
model = DataFile
|
model = DataFile
|
||||||
brief_fields = ['display', 'id', 'path', 'url']
|
brief_fields = ['display', 'id', 'path', 'url']
|
||||||
|
user_permissions = ('core.view_datasource', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -1051,7 +1051,7 @@ class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
)
|
)
|
||||||
device = tables.TemplateColumn(
|
device = tables.TemplateColumn(
|
||||||
verbose_name=_('Device'),
|
verbose_name=_('Device'),
|
||||||
order_by=('_name',),
|
order_by=('device___name',),
|
||||||
template_code=DEVICE_LINK,
|
template_code=DEVICE_LINK,
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
|
@ -192,6 +192,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_site',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -277,6 +278,7 @@ class RackTypeTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'new description',
|
'description': 'new description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_manufacturer',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -321,6 +323,7 @@ class RackTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'status': 'planned',
|
'status': 'planned',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_site', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -409,6 +412,7 @@ class RackReservationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_rack', 'users.view_user')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -488,6 +492,7 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'part_number': 'ABC123',
|
'part_number': 'ABC123',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_manufacturer', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -533,6 +538,7 @@ class ModuleTypeTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'part_number': 'ABC123',
|
'part_number': 'ABC123',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_manufacturer', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -704,6 +710,7 @@ class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_devicetype', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -809,6 +816,7 @@ class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_rearporttemplate', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -946,6 +954,7 @@ class ModuleBayTemplateTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_devicetype', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -986,6 +995,7 @@ class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_devicetype', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1026,6 +1036,7 @@ class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_devicetype', 'dcim.view_manufacturer',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1144,6 +1155,10 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'status': 'failed',
|
'status': 'failed',
|
||||||
}
|
}
|
||||||
|
user_permissions = (
|
||||||
|
'dcim.view_site', 'dcim.view_rack', 'dcim.view_location', 'dcim.view_devicerole', 'dcim.view_devicetype',
|
||||||
|
'extras.view_configtemplate',
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1334,6 +1349,7 @@ class ModuleTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'serial': '1234ABCD',
|
'serial': '1234ABCD',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_modulebay', 'dcim.view_moduletype', 'dcim.view_device')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1400,6 +1416,7 @@ class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = ConsoleServerPort
|
peer_termination_type = ConsoleServerPort
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1442,6 +1459,7 @@ class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIView
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = ConsolePort
|
peer_termination_type = ConsolePort
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1484,6 +1502,7 @@ class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = PowerOutlet
|
peer_termination_type = PowerOutlet
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1523,6 +1542,7 @@ class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = PowerPort
|
peer_termination_type = PowerPort
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1571,6 +1591,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = Interface
|
peer_termination_type = Interface
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1705,6 +1726,7 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = Interface
|
peer_termination_type = Interface
|
||||||
|
user_permissions = ('dcim.view_device', 'dcim.view_rearport')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1763,6 +1785,7 @@ class RearPortTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
peer_termination_type = Interface
|
peer_termination_type = Interface
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1804,6 +1827,7 @@ class ModuleBayTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1844,6 +1868,7 @@ class DeviceBayTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_device', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1907,6 +1932,7 @@ class InventoryItemTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_device', 'dcim.view_manufacturer')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -2203,6 +2229,7 @@ class VirtualChassisTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class PowerPanelTest(APIViewTestCases.APIViewTestCase):
|
class PowerPanelTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
brief_fields = ['description', 'display', 'id', 'name', 'powerfeed_count', 'url']
|
brief_fields = ['description', 'display', 'id', 'name', 'powerfeed_count', 'url']
|
||||||
|
user_permissions = ('dcim.view_site', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -2255,6 +2282,7 @@ class PowerFeedTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'status': 'planned',
|
'status': 'planned',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_powerpanel', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -183,10 +183,13 @@ class ObjectCountsWidget(DashboardWidget):
|
|||||||
for model in get_models_from_content_types(self.config['models']):
|
for model in get_models_from_content_types(self.config['models']):
|
||||||
permission = get_permission_for_model(model, 'view')
|
permission = get_permission_for_model(model, 'view')
|
||||||
if request.user.has_perm(permission):
|
if request.user.has_perm(permission):
|
||||||
url = reverse(get_viewname(model, 'list'))
|
try:
|
||||||
|
url = reverse(get_viewname(model, 'list'))
|
||||||
|
except NoReverseMatch:
|
||||||
|
url = None
|
||||||
qs = model.objects.restrict(request.user, 'view')
|
qs = model.objects.restrict(request.user, 'view')
|
||||||
# Apply any specified filters
|
# Apply any specified filters
|
||||||
if filters := self.config.get('filters'):
|
if url and (filters := self.config.get('filters')):
|
||||||
params = dict_to_querydict(filters)
|
params = dict_to_querydict(filters)
|
||||||
filterset = getattr(resolve(url).func.view_class, 'filterset', None)
|
filterset = getattr(resolve(url).func.view_class, 'filterset', None)
|
||||||
qs = filterset(params, qs).qs
|
qs = filterset(params, qs).qs
|
||||||
|
@ -768,6 +768,7 @@ class FHRPGroupAssignmentTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'priority': 100,
|
'priority': 100,
|
||||||
}
|
}
|
||||||
|
user_permissions = ('ipam.view_fhrpgroup', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -38,7 +38,7 @@ schema = strawberry.Schema(
|
|||||||
query=Query,
|
query=Query,
|
||||||
config=StrawberryConfig(auto_camel_case=False),
|
config=StrawberryConfig(auto_camel_case=False),
|
||||||
extensions=[
|
extensions=[
|
||||||
DjangoOptimizerExtension,
|
DjangoOptimizerExtension(prefetch_custom_queryset=True),
|
||||||
MaxAliasesLimiter(max_alias_count=settings.GRAPHQL_MAX_ALIASES),
|
MaxAliasesLimiter(max_alias_count=settings.GRAPHQL_MAX_ALIASES),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,7 @@ from rest_framework import status
|
|||||||
|
|
||||||
from core.models import ObjectType
|
from core.models import ObjectType
|
||||||
from dcim.models import Site, Location
|
from dcim.models import Site, Location
|
||||||
|
from ipam.models import ASN, RIR
|
||||||
from users.models import ObjectPermission
|
from users.models import ObjectPermission
|
||||||
from utilities.testing import disable_warnings, APITestCase, TestCase
|
from utilities.testing import disable_warnings, APITestCase, TestCase
|
||||||
|
|
||||||
@ -45,7 +46,6 @@ class GraphQLTestCase(TestCase):
|
|||||||
class GraphQLAPITestCase(APITestCase):
|
class GraphQLAPITestCase(APITestCase):
|
||||||
|
|
||||||
@override_settings(LOGIN_REQUIRED=True)
|
@override_settings(LOGIN_REQUIRED=True)
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*', 'auth.user'])
|
|
||||||
def test_graphql_filter_objects(self):
|
def test_graphql_filter_objects(self):
|
||||||
"""
|
"""
|
||||||
Test the operation of filters for GraphQL API requests.
|
Test the operation of filters for GraphQL API requests.
|
||||||
@ -66,6 +66,7 @@ class GraphQLAPITestCase(APITestCase):
|
|||||||
obj_perm.save()
|
obj_perm.save()
|
||||||
obj_perm.users.add(self.user)
|
obj_perm.users.add(self.user)
|
||||||
obj_perm.object_types.add(ObjectType.objects.get_for_model(Location))
|
obj_perm.object_types.add(ObjectType.objects.get_for_model(Location))
|
||||||
|
obj_perm.object_types.add(ObjectType.objects.get_for_model(Site))
|
||||||
|
|
||||||
# A valid request should return the filtered list
|
# A valid request should return the filtered list
|
||||||
url = reverse('graphql')
|
url = reverse('graphql')
|
||||||
@ -75,6 +76,7 @@ class GraphQLAPITestCase(APITestCase):
|
|||||||
data = json.loads(response.content)
|
data = json.loads(response.content)
|
||||||
self.assertNotIn('errors', data)
|
self.assertNotIn('errors', data)
|
||||||
self.assertEqual(len(data['data']['location_list']), 1)
|
self.assertEqual(len(data['data']['location_list']), 1)
|
||||||
|
self.assertIsNotNone(data['data']['location_list'][0]['site'])
|
||||||
|
|
||||||
# An invalid request should return an empty list
|
# An invalid request should return an empty list
|
||||||
query = '{location_list(filters: {site_id: "99999"}) {id site {id}}}' # Invalid site ID
|
query = '{location_list(filters: {site_id: "99999"}) {id site {id}}}' # Invalid site ID
|
||||||
@ -82,3 +84,12 @@ class GraphQLAPITestCase(APITestCase):
|
|||||||
self.assertHttpStatus(response, status.HTTP_200_OK)
|
self.assertHttpStatus(response, status.HTTP_200_OK)
|
||||||
data = json.loads(response.content)
|
data = json.loads(response.content)
|
||||||
self.assertEqual(len(data['data']['location_list']), 0)
|
self.assertEqual(len(data['data']['location_list']), 0)
|
||||||
|
|
||||||
|
# Removing the permissions from location should result in an empty locations list
|
||||||
|
obj_perm.object_types.remove(ObjectType.objects.get_for_model(Location))
|
||||||
|
query = '{site(id: ' + str(sites[0].pk) + ') {id locations {id}}}'
|
||||||
|
response = self.client.post(url, data={'query': query}, format="json", **self.header)
|
||||||
|
self.assertHttpStatus(response, status.HTTP_200_OK)
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertNotIn('errors', data)
|
||||||
|
self.assertEqual(len(data['data']['site']['locations']), 0)
|
||||||
|
@ -992,14 +992,7 @@ brace-expansion@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
|
|
||||||
braces@^3.0.2:
|
braces@^3.0.3, braces@~3.0.2:
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
|
||||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
|
||||||
dependencies:
|
|
||||||
fill-range "^7.0.1"
|
|
||||||
|
|
||||||
braces@~3.0.2:
|
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
|
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
|
||||||
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
||||||
@ -1575,7 +1568,7 @@ file-entry-cache@^6.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache "^3.0.4"
|
flat-cache "^3.0.4"
|
||||||
|
|
||||||
fill-range@^7.0.1, fill-range@^7.1.1:
|
fill-range@^7.1.1:
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
|
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
|
||||||
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
||||||
@ -2190,11 +2183,11 @@ meros@^1.1.4:
|
|||||||
integrity sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==
|
integrity sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==
|
||||||
|
|
||||||
micromatch@^4.0.4:
|
micromatch@^4.0.4:
|
||||||
version "4.0.5"
|
version "4.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||||
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
||||||
dependencies:
|
dependencies:
|
||||||
braces "^3.0.2"
|
braces "^3.0.3"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{% if counts %}
|
{% if counts %}
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
{% for model, count, url in counts %}
|
{% for model, count, url in counts %}
|
||||||
<a href="{{ url }}" class="list-group-item list-group-item-action px-1 py-2">
|
<a {% if url %}href="{{ url }}" {% endif %}class="list-group-item list-group-item-action px-1 py-2">
|
||||||
<div class="d-flex w-100 justify-content-between align-items-center">
|
<div class="d-flex w-100 justify-content-between align-items-center">
|
||||||
{{ model|meta:"verbose_name_plural"|bettertitle }}
|
{{ model|meta:"verbose_name_plural"|bettertitle }}
|
||||||
{% if count is None %}
|
{% if count is None %}
|
||||||
|
@ -210,6 +210,7 @@ class ContactAssignmentTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'priority': ContactPriorityChoices.PRIORITY_INACTIVE,
|
'priority': ContactPriorityChoices.PRIORITY_INACTIVE,
|
||||||
}
|
}
|
||||||
|
user_permissions = ('tenancy.view_contact', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
BIN
netbox/translations/cs/LC_MESSAGES/django.mo
Normal file
BIN
netbox/translations/cs/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
netbox/translations/da/LC_MESSAGES/django.mo
Normal file
BIN
netbox/translations/da/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
netbox/translations/it/LC_MESSAGES/django.mo
Normal file
BIN
netbox/translations/it/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
netbox/translations/nl/LC_MESSAGES/django.mo
Normal file
BIN
netbox/translations/nl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
netbox/translations/pl/LC_MESSAGES/django.mo
Normal file
BIN
netbox/translations/pl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -253,6 +253,7 @@ class VMInterfaceTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
graphql_base_name = 'vm_interface'
|
graphql_base_name = 'vm_interface'
|
||||||
|
user_permissions = ('virtualization.view_virtualmachine', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -342,6 +343,7 @@ class VirtualDiskTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'size': 888,
|
'size': 888,
|
||||||
}
|
}
|
||||||
graphql_base_name = 'virtual_disk'
|
graphql_base_name = 'virtual_disk'
|
||||||
|
user_permissions = ('virtualization.view_virtualmachine', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -116,6 +116,7 @@ class TunnelTerminationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
'role': TunnelTerminationRoleChoices.ROLE_PEER,
|
'role': TunnelTerminationRoleChoices.ROLE_PEER,
|
||||||
}
|
}
|
||||||
|
user_permissions = ('vpn.view_tunnel', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -430,6 +431,7 @@ class IPSecPolicyTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class IPSecProfileTest(APIViewTestCases.APIViewTestCase):
|
class IPSecProfileTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = IPSecProfile
|
model = IPSecProfile
|
||||||
brief_fields = ['description', 'display', 'id', 'name', 'url']
|
brief_fields = ['description', 'display', 'id', 'name', 'url']
|
||||||
|
user_permissions = ('vpn.view_ikepolicy', 'vpn.view_ipsecpolicy')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -558,6 +560,7 @@ class L2VPNTest(APIViewTestCases.APIViewTestCase):
|
|||||||
class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
|
class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = L2VPNTermination
|
model = L2VPNTermination
|
||||||
brief_fields = ['display', 'id', 'l2vpn', 'url']
|
brief_fields = ['display', 'id', 'l2vpn', 'url']
|
||||||
|
user_permissions = ('dcim.view_location', 'vpn.view_l2vpn')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -116,6 +116,7 @@ class WirelessLinkTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'distance': 100,
|
'distance': 100,
|
||||||
'distance_unit': 'm',
|
'distance_unit': 'm',
|
||||||
}
|
}
|
||||||
|
user_permissions = ('dcim.view_interface', )
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Django==5.0.8
|
Django==5.0.9
|
||||||
django-cors-headers==4.4.0
|
django-cors-headers==4.4.0
|
||||||
django-debug-toolbar==4.4.6
|
django-debug-toolbar==4.4.6
|
||||||
django-filter==24.3
|
django-filter==24.3
|
||||||
@ -8,7 +8,7 @@ django-mptt==0.16.0
|
|||||||
django-pglocks==1.0.4
|
django-pglocks==1.0.4
|
||||||
django-prometheus==2.3.1
|
django-prometheus==2.3.1
|
||||||
django-redis==5.4.0
|
django-redis==5.4.0
|
||||||
django-rich==1.10.0
|
django-rich==1.11.0
|
||||||
django-rq==2.10.2
|
django-rq==2.10.2
|
||||||
django-taggit==6.0.0
|
django-taggit==6.0.0
|
||||||
django-tables2==2.7.0
|
django-tables2==2.7.0
|
||||||
@ -20,8 +20,8 @@ feedparser==6.0.11
|
|||||||
gunicorn==23.0.0
|
gunicorn==23.0.0
|
||||||
Jinja2==3.1.4
|
Jinja2==3.1.4
|
||||||
Markdown==3.7
|
Markdown==3.7
|
||||||
mkdocs-material==9.5.33
|
mkdocs-material==9.5.34
|
||||||
mkdocstrings[python-legacy]==0.25.2
|
mkdocstrings[python-legacy]==0.26.0
|
||||||
netaddr==1.3.0
|
netaddr==1.3.0
|
||||||
nh3==0.2.18
|
nh3==0.2.18
|
||||||
Pillow==10.4.0
|
Pillow==10.4.0
|
||||||
@ -30,7 +30,7 @@ PyYAML==6.0.2
|
|||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
social-auth-app-django==5.4.2
|
social-auth-app-django==5.4.2
|
||||||
social-auth-core==4.5.4
|
social-auth-core==4.5.4
|
||||||
strawberry-graphql==0.237.3
|
strawberry-graphql==0.239.2
|
||||||
strawberry-graphql-django==0.47.1
|
strawberry-graphql-django==0.47.1
|
||||||
svgwrite==1.4.3
|
svgwrite==1.4.3
|
||||||
tablib==3.6.1
|
tablib==3.6.1
|
||||||
|
Loading…
Reference in New Issue
Block a user