internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: netbox-community/netbox

Issue:
Remove backward compatibility for old ActionsMixin `actions` attribute
### Proposed Changes

The old `actions` and `action_perms` attributes on the ActionsMixin class were merged in v3.7 under #13550, with backward compatibility retained for the v3.7 release. This change removes that backward compatibility.

### Justification

Removes obsolete code.

### Impact

Any plugins which utilize ActionsMixin will need to update their relevant view classes to use the new declaration format for `actions`. See #13550 for examples.


Discussion:

Resolving patch:
diff --git a/netbox/netbox/views/generic/mixins.py b/netbox/netbox/views/generic/mixins.py
--- a/netbox/netbox/views/generic/mixins.py
+++ b/netbox/netbox/views/generic/mixins.py
@@ -1,5 +1,3 @@
-import warnings
-
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
 from utilities.permissions import get_permission_for_model
 
@@ -26,38 +24,11 @@ def get_permitted_actions(self, user, model=None):
         """
         model = model or self.queryset.model
 
-        # TODO: Remove backward compatibility in Netbox v4.0
-        # Determine how permissions are being mapped to actions for the view
-        if hasattr(self, 'action_perms'):
-            # Backward compatibility for <3.7
-            permissions_map = self.action_perms
-            warnings.warn(
-                "Setting action_perms on views is deprecated and will be removed in NetBox v4.0. Use actions instead.",
-                DeprecationWarning
-            )
-        elif type(self.actions) is dict:
-            # New actions format (3.7+)
-            permissions_map = self.actions
-        else:
-            # actions is still defined as a list or tuple (<3.7) but no custom mapping is defined; use the old
-            # default mapping
-            permissions_map = {
-                'add': {'add'},
-                'import': {'add'},
-                'bulk_edit': {'change'},
-                'bulk_delete': {'delete'},
-            }
-            warnings.warn(
-                "View actions should be defined as a dictionary mapping. Support for the legacy list format will be "
-                "removed in NetBox v4.0.",
-                DeprecationWarning
-            )
-
         # Resolve required permissions for each action
         permitted_actions = []
         for action in self.actions:
             required_permissions = [
-                get_permission_for_model(model, name) for name in permissions_map.get(action, set())
+                get_permission_for_model(model, name) for name in self.actions.get(action, set())
             ]
             if not required_permissions or user.has_perms(required_permissions):
                 permitted_actions.append(action)


Test patch:
Repository: netbox-community/netbox

Issue:
Drop support for Python 3.8 and 3.9
### Proposed Changes

Increase the minimum supported Python version from 3.8 to 3.10. Remove tests for Python <3.10.

### Justification

We'll be adopting Django 5.0 in NetBox v4.0 (see #14637), which [requires Python 3.10 or later](https://docs.djangoproject.com/en/5.0/releases/5.0/#python-compatibility).

Additionally, Python versions earlier than 3.11 are no longer receiving bug fixes per the [Python release cycle](https://devguide.python.org/versions/).

### Impact

NetBox deployments running Python 3.9 or earlier will need to upgrade their Python version to 3.10 or later.


Discussion:
I'm all for it and don't see any glaring issues up to and including 3.11.  3.12 opens a lot of cases in downstreams of downstreams to need updates or unpinning of specific older versions.

Resolving patch:
diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py
--- a/netbox/netbox/settings.py
+++ b/netbox/netbox/settings.py
@@ -3,17 +3,18 @@
 import importlib.util
 import os
 import platform
-import requests
 import sys
 import warnings
 from urllib.parse import urlencode, urlsplit
 
 import django
+import requests
 from django.contrib.messages import constants as messages
 from django.core.exceptions import ImproperlyConfigured, ValidationError
 from django.core.validators import URLValidator
 from django.utils.encoding import force_str
 from django.utils.translation import gettext_lazy as _
+
 try:
     import sentry_sdk
 except ModuleNotFoundError:
@@ -37,9 +38,9 @@
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 # Validate Python version
-if sys.version_info < (3, 8):
+if sys.version_info < (3, 10):
     raise RuntimeError(
-        f"NetBox requires Python 3.8 or later. (Currently installed: Python {platform.python_version()})"
+        f"NetBox requires Python 3.10 or later. (Currently installed: Python {platform.python_version()})"
     )
 
 #


Test patch:
diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py
--- a/netbox/dcim/tests/test_views.py
+++ b/netbox/dcim/tests/test_views.py
@@ -1,9 +1,5 @@
 from decimal import Decimal
-try:
-    from zoneinfo import ZoneInfo
-except ImportError:
-    # Python 3.8
-    from backports.zoneinfo import ZoneInfo
+from zoneinfo import ZoneInfo
 
 import yaml
 from django.contrib.auth import get_user_model
Repository: netbox-community/netbox

Issue:
Add support for Python 3.12
### Proposed Changes

Document and test for Python 3.12 support in addition to 3.10 and 3.11.

### Justification

Declare support for running NetBox v4.0 on Python 3.12. Django 5.0 also [supports Python 3.12](https://docs.djangoproject.com/en/5.0/releases/5.0/#python-compatibility).


Discussion:

Resolving patch:
diff --git a/netbox/dcim/management/commands/trace_paths.py b/netbox/dcim/management/commands/trace_paths.py
--- a/netbox/dcim/management/commands/trace_paths.py
+++ b/netbox/dcim/management/commands/trace_paths.py
@@ -34,7 +34,7 @@ def draw_progress_bar(self, percentage):
         Draw a simple progress bar 20 increments wide illustrating the specified percentage.
         """
         bar_size = int(percentage / 5)
-        self.stdout.write(f"\r  [{'#' * bar_size}{' ' * (20-bar_size)}] {int(percentage)}%", ending='')
+        self.stdout.write(f"\r  [{'#' * bar_size}{' ' * (20 - bar_size)}] {int(percentage)}%", ending='')
 
     def handle(self, *model_names, **options):
 
diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py
--- a/netbox/dcim/models/devices.py
+++ b/netbox/dcim/models/devices.py
@@ -222,7 +222,7 @@ def get_absolute_url(self):
 
     @property
     def get_full_name(self):
-        return f"{ self.manufacturer } { self.model }"
+        return f"{self.manufacturer} {self.model}"
 
     def to_yaml(self):
         data = {


Test patch:
diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py
--- a/netbox/dcim/tests/test_api.py
+++ b/netbox/dcim/tests/test_api.py
@@ -2105,7 +2105,7 @@ def setUpTestData(cls):
             for j in range(0, 13):
                 interfaces.append(
                     # Interface name starts with parent device's position in VC; e.g. 1/1, 1/2, 1/3...
-                    Interface(device=device, name=f'{i%3+1}/{j}', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
+                    Interface(device=device, name=f'{i % 3 + 1}/{j}', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
                 )
         Interface.objects.bulk_create(interfaces)
 
diff --git a/netbox/users/tests/test_api.py b/netbox/users/tests/test_api.py
--- a/netbox/users/tests/test_api.py
+++ b/netbox/users/tests/test_api.py
@@ -264,9 +264,9 @@ def setUpTestData(cls):
 
         for i in range(3):
             objectpermission = ObjectPermission(
-                name=f'Permission {i+1}',
+                name=f'Permission {i + 1}',
                 actions=['view', 'add', 'change', 'delete'],
-                constraints={'name': f'TEST{i+1}'}
+                constraints={'name': f'TEST{i + 1}'}
             )
             objectpermission.save()
             objectpermission.object_types.add(object_type)
Repository: netbox-community/netbox

Issue:
related_name should not be translated
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.8

### Steps to Reproduce

If you enable the translation function, an error appears. This is due to the fact that in `netbox/dcim/models/device_components.py` in the `DeviceBay` class the translation was made `related_name`.

### Expected Behavior

remove translation for `related_name`.

### Observed Behavior

Nonetype Object Has No Attribute model


Discussion:

Resolving patch:
diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py
--- a/netbox/dcim/models/device_components.py
+++ b/netbox/dcim/models/device_components.py
@@ -1115,7 +1115,7 @@ class DeviceBay(ComponentModel, TrackingModelMixin):
     installed_device = models.OneToOneField(
         to='dcim.Device',
         on_delete=models.SET_NULL,
-        related_name=_('parent_bay'),
+        related_name='parent_bay',
         blank=True,
         null=True
     )


Test patch:
Repository: netbox-community/netbox

Issue:
DH Group 15 (3072) not selectable in UI
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.11

### Steps to Reproduce

1. Open vpn/ike proposals in UI
2. Try to select DH group 15

### Expected Behavior

A dropdown containing group 15

### Observed Behavior

DH group 15 is missing


Discussion:

Resolving patch:
diff --git a/netbox/vpn/choices.py b/netbox/vpn/choices.py
--- a/netbox/vpn/choices.py
+++ b/netbox/vpn/choices.py
@@ -179,6 +179,7 @@ class DHGroupChoices(ChoiceSet):
         (GROUP_2, _('Group {n}').format(n=2)),
         (GROUP_5, _('Group {n}').format(n=5)),
         (GROUP_14, _('Group {n}').format(n=14)),
+        (GROUP_15, _('Group {n}').format(n=15)),
         (GROUP_16, _('Group {n}').format(n=16)),
         (GROUP_17, _('Group {n}').format(n=17)),
         (GROUP_18, _('Group {n}').format(n=18)),


Test patch:
Repository: netbox-community/netbox

Issue:
Quick search breaks available IPs search results
### Deployment Type

Self-hosted

### NetBox Version

3.7.0

### Python Version

3.10

### Steps to Reproduce

View prefix and use "quick search" to filter ip addresses

### Expected Behavior

Available IPs should not change. I would argue that available IPs should not show up in quick search results at all. 

### Observed Behavior

The available IPs increases with the number of IP addresses filtered out. The IPs are however not actually available. Clicking on the available IPs goes onto provision an IP that is already assigned. 
![image](https://github.com/netbox-community/netbox/assets/17918019/60269f99-dffe-4c65-a022-51a0289258c4)



Discussion:
Looks like a regression introduced in e4cb0c3cc2738369c71484ff188a6a741c510351

Resolving patch:
diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py
--- a/netbox/ipam/views.py
+++ b/netbox/ipam/views.py
@@ -604,7 +604,7 @@ def get_children(self, request, parent):
         return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant', 'tenant__group')
 
     def prep_table_data(self, request, queryset, parent):
-        if not get_table_ordering(request, self.table):
+        if not request.GET.get('q') and not get_table_ordering(request, self.table):
             return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
         return queryset
 


Test patch:
Repository: netbox-community/netbox

Issue:
When adding a Custom Field via API it does not accept null values for non-required fields in version 3.7.0
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.8

### Steps to Reproduce

1. An error is generated when a request is sent to create a Custom Field
```
curl -X 'POST' \
  'http://0.0.0.0/api/extras/custom-fields/' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'X-CSRFTOKEN: zM1Spw2GkaObXREv7mZHEvlIXdN7oG2sb8dGpmtta8x34hvg1Hjqnzwn24MqYOCR' \
  -d '{
  "content_types": [
    "dcim.rearport"
  ],
  "type": "text",
  "object_type": null,
  "name": "Test",
  "label": "string",
  "group_name": "string",
  "description": "string",
  "required": true,
  "search_weight": 32767,
  "filter_logic": "disabled",
  "ui_visible": "always",
  "ui_editable": "yes",
  "is_cloneable": true,
  "default": "string",
  "weight": 32767,
  "validation_minimum": null,
  "validation_maximum": null,
  "validation_regex": "string",
  "choice_set": null
}'
``` 


### Expected Behavior

Add the Custom Field as defined.

### Observed Behavior

The following error occurs when the request is submitted:

Code: 400
Details: Error: Bad Request
Response body:
```
{
  "object_type": [
    "This field may not be null."
  ],
  "choice_set": [
    "This field may not be null."
  ]
}
``` 

If the fields are removed from the request the behavior is as expected, however it is not a solution since I do not directly control what is sent in the HTTP request and it would not allow passing the fields from a non-null value to a null one.

Adding an Custom Field via GUI is not a problem (only the required fields are filled)


Discussion:
Field Choice Set has the same behavior with the "base_choices" field

Resolving patch:
diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py
--- a/netbox/extras/api/serializers.py
+++ b/netbox/extras/api/serializers.py
@@ -126,11 +126,15 @@ class CustomFieldSerializer(ValidatedModelSerializer):
     type = ChoiceField(choices=CustomFieldTypeChoices)
     object_type = ContentTypeField(
         queryset=ContentType.objects.all(),
-        required=False
+        required=False,
+        allow_null=True
     )
     filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
     data_type = serializers.SerializerMethodField()
-    choice_set = NestedCustomFieldChoiceSetSerializer(required=False)
+    choice_set = NestedCustomFieldChoiceSetSerializer(
+        required=False,
+        allow_null=True
+    )
     ui_visible = ChoiceField(choices=CustomFieldUIVisibleChoices, required=False)
     ui_editable = ChoiceField(choices=CustomFieldUIEditableChoices, required=False)
 


Test patch:
Repository: netbox-community/netbox

Issue:
Importing IKE proposal without authentication method is not possible
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.11

### Steps to Reproduce

Go to **VPN - IKE Proposals - Add**
1. Name = GUITEST
2. Authentication method = PSK
3. Encryption algorithm = 256-bit AES (GCM)
4. Group = Group 20
5. Create

(= is successful)

Go to **VPN - IKE Proposals - Import**, use the same fields as above:

```
name,authentication_method,encryption_algorithm,group
IMPORTTEST,preshared-keys,aes-256-gcm,20
```


### Expected Behavior

IKE proposal is imported successfully.

### Observed Behavior

Error is shown:

**Record 1 authentication_algorithm: This field is required.** 

In the import field options the `authentication_algorithm `field is shown as required even though it is not required in GUI.

Also, in the `authentication_algorithm `value list there is no "empty" option to use, thus it is not possible to import IKE proposals that use GCM, unless you fake the algorithm during the import.

Also note that if authentication algorithm is nevertheless set and you want to remove it, you have to **single-edit** the proposal: it is not possible to select all proposals in the list and use **Edit Selected**, as it is not possible to clear the field there.

Related to #14499 where GUI requirement for the authentication method was relaxed.


Discussion:
Seems like this was an oversight during the work on #14499.
A similar discrepancy exists with the `encryption_algorithm` and `authentication_algorithm` fields on the IPSec proposal bulk import form.

Resolving patch:
diff --git a/netbox/vpn/forms/bulk_import.py b/netbox/vpn/forms/bulk_import.py
--- a/netbox/vpn/forms/bulk_import.py
+++ b/netbox/vpn/forms/bulk_import.py
@@ -151,7 +151,8 @@ class IKEProposalImportForm(NetBoxModelImportForm):
     )
     authentication_algorithm = CSVChoiceField(
         label=_('Authentication algorithm'),
-        choices=AuthenticationAlgorithmChoices
+        choices=AuthenticationAlgorithmChoices,
+        required=False
     )
     group = CSVChoiceField(
         label=_('Group'),
@@ -191,11 +192,13 @@ class Meta:
 class IPSecProposalImportForm(NetBoxModelImportForm):
     encryption_algorithm = CSVChoiceField(
         label=_('Encryption algorithm'),
-        choices=EncryptionAlgorithmChoices
+        choices=EncryptionAlgorithmChoices,
+        required=False
     )
     authentication_algorithm = CSVChoiceField(
         label=_('Authentication algorithm'),
-        choices=AuthenticationAlgorithmChoices
+        choices=AuthenticationAlgorithmChoices,
+        required=False
     )
 
     class Meta:
@@ -209,7 +212,8 @@ class Meta:
 class IPSecPolicyImportForm(NetBoxModelImportForm):
     pfs_group = CSVChoiceField(
         label=_('Diffie-Hellman group for Perfect Forward Secrecy'),
-        choices=DHGroupChoices
+        choices=DHGroupChoices,
+        required=False
     )
     proposals = CSVModelMultipleChoiceField(
         queryset=IPSecProposal.objects.all(),


Test patch:
Repository: netbox-community/netbox

Issue:
Only one event rule triggers for a content type
### Deployment Type

Self-hosted

### NetBox Version

v3.7.0

### Python Version

3.11

### Steps to Reproduce

Setup:

1. Create a webhook: Name = Test, URL = http://127.0.0.1:9000
2. Create event rule 1:
    - Name = Rule 1
    - Content types = Prefix
    - select Updates
    - Condition = `{ "and": [{"attr": "status.value", "value": "deprecated"}]}`
    - Action type = Webhook
    - Webhook = Test
3. Create event rule 2:
    - Name = Rule 2
    - Content types = Prefix
    - select Updates
    - Condition = `{ "and": [{"attr": "status.value", "value": "active"}]}`
    - Action type = Webhook
    - Webhook = Test
4. Start webhook receiver (`python manage.py webhook_receiver`), or observe the webhooks happen in some other way

(Sorry, couldn't figure out the correct condition syntax without using the "and" operator)

Demo:

5. Create a prefix, like 10.1.2.0/24, status = Active (the defaults)
6. Edit the prefix: change its status to **Deprecated**
7. Edit the prefix again: change its status to **Active**


### Expected Behavior

Webhook is run **twice**: first when prefix status was changed to **Deprecated** (step 6), second when changed to **Active** again (step 7).

### Observed Behavior

Webhook is run **only once**, that's in step 6, but not in step 7.

Additionally: If Rule 1 is disabled, and steps 6 and 7 are executed again, now the webhook is run in step 7.

Looks like only the first enabled event rule is run for a specific object type.


Discussion:

Resolving patch:
diff --git a/netbox/extras/events.py b/netbox/extras/events.py
--- a/netbox/extras/events.py
+++ b/netbox/extras/events.py
@@ -81,7 +81,7 @@ def process_event_rules(event_rules, model_name, event, data, username, snapshot
 
         # Evaluate event rule conditions (if any)
         if not event_rule.eval_conditions(data):
-            return
+            continue
 
         # Webhooks
         if event_rule.action_type == EventRuleActionChoices.WEBHOOK:


Test patch:
Repository: netbox-community/netbox

Issue:
Tunnel group selection when creating new tunnel
### Deployment Type

Self-hosted

### NetBox Version

v3.7.1

### Python Version

3.9

### Steps to Reproduce

1. Section "VPN"
2. Add new tunnel

### Expected Behavior

The form contains a field for selecting the tunnel group.

### Observed Behavior

No such field. A tunnel group can only be assigned by editing an already added tunnel.


Discussion:

Resolving patch:
diff --git a/netbox/vpn/forms/model_forms.py b/netbox/vpn/forms/model_forms.py
--- a/netbox/vpn/forms/model_forms.py
+++ b/netbox/vpn/forms/model_forms.py
@@ -141,7 +141,7 @@ class TunnelCreateForm(TunnelForm):
     )
 
     fieldsets = (
-        (_('Tunnel'), ('name', 'status', 'encapsulation', 'description', 'tunnel_id', 'tags')),
+        (_('Tunnel'), ('name', 'status', 'group', 'encapsulation', 'description', 'tunnel_id', 'tags')),
         (_('Security'), ('ipsec_profile',)),
         (_('Tenancy'), ('tenant_group', 'tenant')),
         (_('First Termination'), (


Test patch:
Repository: netbox-community/netbox

Issue:
Data Source custom fields are not available through REST API
### Deployment Type

Self-hosted

### NetBox Version

v3.7.1

### Python Version

3.10

### Steps to Reproduce

1. Create custom field and assign it to Data Source.
2. Create Data Source and fill out respective custom field via GUI.
3. Try to get the information about created Data Source through REST API - there will be no "custom_fields" field.
4. If you try to create Data Source through REST API "custom_fields" field will be ignored.

### Expected Behavior

There should be consistency in interaction with Data Sources (or any other model). If a user can assign custom fields to this model through web GUI, then the same opportunity should also exist for REST API.

All that's required to do for this issue is just add "custom_fields" here
https://github.com/netbox-community/netbox/blob/develop/netbox/core/api/serializers.py#L37

### Observed Behavior

Neither reading nor changing "custom_fields" value for a Data Source is available through REST API.


Discussion:

Resolving patch:
diff --git a/netbox/core/api/serializers.py b/netbox/core/api/serializers.py
--- a/netbox/core/api/serializers.py
+++ b/netbox/core/api/serializers.py
@@ -36,7 +36,7 @@ class Meta:
         model = DataSource
         fields = [
             'id', 'url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', 'comments',
-            'parameters', 'ignore_rules', 'created', 'last_updated', 'file_count',
+            'parameters', 'ignore_rules', 'custom_fields', 'created', 'last_updated', 'file_count',
         ]
 
 


Test patch: