Compare commits

...

4 Commits

Author SHA1 Message Date
Martin Hauser
a696f71656 Merge 60fce84c96 into f0507d00bf 2025-12-10 21:30:01 +01:00
Martin Hauser
60fce84c96 feat(ipam): Normalize numeric ranges in API output
Adds logic to handle numeric range fields in API responses by
converting them into inclusive `[low, high]` pairs for consistent
behavior. Updates test cases with `vid_ranges` fields to reflect the
changes.

Closes #20491
2025-12-10 21:11:23 +01:00
github-actions
f0507d00bf Update source translation strings
Some checks failed
CI / build (20.x, 3.10) (push) Has been cancelled
CI / build (20.x, 3.11) (push) Has been cancelled
CI / build (20.x, 3.12) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled
2025-12-10 05:02:48 +00:00
Arthur Hanson
77b389f105 Fixes #20873: fix webhooks with image fields (#20955) 2025-12-09 22:06:11 -06:00
5 changed files with 364 additions and 346 deletions

View File

@@ -119,7 +119,9 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non
if snapshots:
params["snapshots"] = snapshots
if request:
params["request"] = copy_safe_request(request)
# Exclude FILES - webhooks don't need uploaded files,
# which can cause pickle errors with Pillow.
params["request"] = copy_safe_request(request, include_files=False)
# Enqueue the task
rq_queue.enqueue(

View File

@@ -1071,14 +1071,17 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
{
'name': 'VLAN Group 4',
'slug': 'vlan-group-4',
'vid_ranges': [[1, 4094]]
},
{
'name': 'VLAN Group 5',
'slug': 'vlan-group-5',
'vid_ranges': [[1, 4094]]
},
{
'name': 'VLAN Group 6',
'slug': 'vlan-group-6',
'vid_ranges': [[1, 4094]]
},
]
bulk_update_data = {

File diff suppressed because it is too large Load Diff

View File

@@ -35,27 +35,34 @@ class NetBoxFakeRequest:
# Utility functions
#
def copy_safe_request(request):
def copy_safe_request(request, include_files=True):
"""
Copy selected attributes from a request object into a new fake request object. This is needed in places where
thread safe pickling of the useful request data is needed.
Args:
request: The original request object
include_files: Whether to include request.FILES.
"""
meta = {
k: request.META[k]
for k in HTTP_REQUEST_META_SAFE_COPY
if k in request.META and isinstance(request.META[k], str)
}
return NetBoxFakeRequest({
data = {
'META': meta,
'COOKIES': request.COOKIES,
'POST': request.POST,
'GET': request.GET,
'FILES': request.FILES,
'user': request.user,
'method': request.method,
'path': request.path,
'id': getattr(request, 'id', None), # UUID assigned by middleware
})
}
if include_files:
data['FILES'] = request.FILES
return NetBoxFakeRequest(data)
def get_client_ip(request, additional_headers=()):

View File

@@ -141,8 +141,8 @@ class ModelTestCase(TestCase):
elif value and type(field) is GenericForeignKey:
model_dict[key] = value.pk
# Handle API output
elif api:
# Replace ContentType numeric IDs with <app_label>.<model>
if type(getattr(instance, key)) in (ContentType, ObjectType):
object_type = ObjectType.objects.get(pk=value)
@@ -152,9 +152,13 @@ class ModelTestCase(TestCase):
elif type(value) is IPNetwork:
model_dict[key] = str(value)
else:
field = instance._meta.get_field(key)
# Normalize arrays of numeric ranges (e.g. VLAN IDs or port ranges).
# DB uses canonical half-open [lo, hi) via NumericRange; API uses inclusive [lo, hi].
# Convert to inclusive pairs for stable API comparisons.
elif type(field) is ArrayField and issubclass(type(field.base_field), RangeField):
model_dict[key] = [[r.lower, r.upper - 1] for r in value]
else:
# Convert ArrayFields to CSV strings
if type(field) is ArrayField:
if getattr(field.base_field, 'choices', None):