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

Issue:
The bookmark widget breaks the frontpage when LOGIN_REQUIRED is False
### NetBox version

v3.6.0-beta2

### Python version

3.11

### Steps to Reproduce

1. Set `LOGIN_REQUIRED = False` in configuration.py
2. Open the frontpage without a logged in session

### Expected Behavior

The home view should render

### Observed Behavior

The following exception is thrown:

`Field 'id' expected a number but got <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7f765c2bf150>>.`

Issue is here:

https://github.com/netbox-community/netbox/blob/5709bc3b2b60597114555a8ed3f70ee4703a483f/netbox/extras/dashboard/widgets.py#L349

request.user is passed to the filter regardless of the user being logged in or not.


Discussion:
As a sidenote, I think it would be logical to have a catchall exception handler when rendering a widget, which would log the exception and show an error in the widget box instead of breaking the home view.

Resolving patch:
diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py
--- a/netbox/extras/dashboard/widgets.py
+++ b/netbox/extras/dashboard/widgets.py
@@ -346,13 +346,16 @@ class ConfigForm(WidgetConfigForm):
     def render(self, request):
         from extras.models import Bookmark
 
-        bookmarks = Bookmark.objects.filter(user=request.user).order_by(self.config['order_by'])
-        if object_types := self.config.get('object_types'):
-            models = get_models_from_content_types(object_types)
-            conent_types = ContentType.objects.get_for_models(*models).values()
-            bookmarks = bookmarks.filter(object_type__in=conent_types)
-        if max_items := self.config.get('max_items'):
-            bookmarks = bookmarks[:max_items]
+        if request.user.is_anonymous:
+            bookmarks = list()
+        else:
+            bookmarks = Bookmark.objects.filter(user=request.user).order_by(self.config['order_by'])
+            if object_types := self.config.get('object_types'):
+                models = get_models_from_content_types(object_types)
+                conent_types = ContentType.objects.get_for_models(*models).values()
+                bookmarks = bookmarks.filter(object_type__in=conent_types)
+            if max_items := self.config.get('max_items'):
+                bookmarks = bookmarks[:max_items]
 
         return render_to_string(self.template_name, {
             'bookmarks': bookmarks,


Test patch:
Repository: netbox-community/netbox

Issue:
Current Cofig page leading to AttributeError
### NetBox version

v3.6.0

### Python version

3.10

### Steps to Reproduce

1. Navigate to Admin > Configuration > Current Config


### Expected Behavior

Not to be returned a server error

### Observed Behavior

Page returns HTTP 500 with:
```
<class 'AttributeError'>

'NoneType' object has no attribute '_meta'

Python version: 3.10.12
Netbox version: 3.6.0
Plugins: None installed
```


Discussion:

Resolving patch:
diff --git a/netbox/core/views.py b/netbox/core/views.py
--- a/netbox/core/views.py
+++ b/netbox/core/views.py
@@ -2,6 +2,7 @@
 from django.shortcuts import get_object_or_404, redirect
 
 from extras.models import ConfigRevision
+from netbox.config import get_config
 from netbox.views import generic
 from netbox.views.generic.base import BaseObjectView
 from utilities.utils import count_related
@@ -152,4 +153,9 @@ class ConfigView(generic.ObjectView):
     queryset = ConfigRevision.objects.all()
 
     def get_object(self, **kwargs):
-        return self.queryset.first()
+        if config := self.queryset.first():
+            return config
+        # Instantiate a dummy default config if none has been created yet
+        return ConfigRevision(
+            data=get_config().defaults
+        )
diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py
--- a/netbox/extras/models/models.py
+++ b/netbox/extras/models/models.py
@@ -723,6 +723,8 @@ class Meta:
         verbose_name_plural = _('config revisions')
 
     def __str__(self):
+        if not self.pk:
+            return gettext('Default configuration')
         if self.is_active:
             return gettext('Current configuration')
         return gettext('Config revision #{id}').format(id=self.pk)
@@ -733,6 +735,8 @@ def __getattr__(self, item):
         return super().__getattribute__(item)
 
     def get_absolute_url(self):
+        if not self.pk:
+            return reverse('core:config')  # Default config view
         return reverse('extras:configrevision', args=[self.pk])
 
     def activate(self):


Test patch:
Repository: netbox-community/netbox

Issue:
Enable controlling the display of navigation menu items depending on the user's `is_staff` status
### NetBox version

v3.6.0

### Feature type

New functionality

### Proposed functionality

Add an optional `staff_only` attribute to the MenuItem class, which defaults to False if not set. Any navigation menu item for which `staff_only` is True will be displayed only if the user's `is_staff` field is True.

(I also considered proposing a `superuser_only` attribute, but worried that might encourage poor practice concerning the assignment of permissions.)

### Use case

This will allow more fine-grained control over the display of individual menu items, beyond the permissions evaluation logic that's currently in place.

This was prompted by and is necessary to resolve #13620.

### Database changes

N/A

### External dependencies

N/A


Discussion:

Resolving patch:
diff --git a/netbox/extras/plugins/navigation.py b/netbox/extras/plugins/navigation.py
--- a/netbox/extras/plugins/navigation.py
+++ b/netbox/extras/plugins/navigation.py
@@ -36,9 +36,10 @@ class PluginMenuItem:
     permissions = []
     buttons = []
 
-    def __init__(self, link, link_text, permissions=None, buttons=None):
+    def __init__(self, link, link_text, staff_only=False, permissions=None, buttons=None):
         self.link = link
         self.link_text = link_text
+        self.staff_only = staff_only
         if permissions is not None:
             if type(permissions) not in (list, tuple):
                 raise TypeError("Permissions must be passed as a tuple or list.")
diff --git a/netbox/netbox/navigation/__init__.py b/netbox/netbox/navigation/__init__.py
--- a/netbox/netbox/navigation/__init__.py
+++ b/netbox/netbox/navigation/__init__.py
@@ -34,6 +34,7 @@ class MenuItem:
     link: str
     link_text: str
     permissions: Optional[Sequence[str]] = ()
+    staff_only: Optional[bool] = False
     buttons: Optional[Sequence[MenuItemButton]] = ()
 
 
diff --git a/netbox/utilities/templatetags/navigation.py b/netbox/utilities/templatetags/navigation.py
--- a/netbox/utilities/templatetags/navigation.py
+++ b/netbox/utilities/templatetags/navigation.py
@@ -26,11 +26,14 @@ def nav(context: Context) -> Dict:
         for group in menu.groups:
             items = []
             for item in group.items:
-                if user.has_perms(item.permissions):
-                    buttons = [
-                        button for button in item.buttons if user.has_perms(button.permissions)
-                    ]
-                    items.append((item, buttons))
+                if not user.has_perms(item.permissions):
+                    continue
+                if item.staff_only and not user.is_staff:
+                    continue
+                buttons = [
+                    button for button in item.buttons if user.has_perms(button.permissions)
+                ]
+                items.append((item, buttons))
             if items:
                 groups.append((group, items))
         if groups:


Test patch:
Repository: netbox-community/netbox

Issue:
There is a bug where the "Renderd Config" tab under the device view is hidden, but the view is still accessible.
### NetBox version

v3.5.9

### Python version

3.10

### Steps to Reproduce

1. Create a user with all permissions (admin) and a user without `extras.view_configtemplate` permissions (user).
2. Open some device view. admin has the "Renderd Config" tab, but user does not.
3. Add "render-config/" to the URL of the browser opened with user privileges. This will allow access to the hidden "Renderd Config".

### Expected Behavior

The "Renderd Config" tab is visible regardless of the permissions of `extras.view_configtemplate`.

I am aware that this behavior is more correct according to the previous bug report.
https://github.com/netbox-community/netbox/issues/13543

### Observed Behavior

The "Renderd Config" tab is hidden by the permissions of `extras.view_configtemplate`.


Discussion:

Resolving patch:
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -2033,7 +2033,6 @@ class DeviceRenderConfigView(generic.ObjectView):
     template_name = 'dcim/device/render_config.html'
     tab = ViewTab(
         label=_('Render Config'),
-        permission='extras.view_configtemplate',
         weight=2100
     )
 
diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py
--- a/netbox/virtualization/views.py
+++ b/netbox/virtualization/views.py
@@ -397,7 +397,6 @@ class VirtualMachineRenderConfigView(generic.ObjectView):
     template_name = 'virtualization/virtualmachine/render_config.html'
     tab = ViewTab(
         label=_('Render Config'),
-        permission='extras.view_configtemplate',
         weight=2100
     )
 


Test patch:
Repository: netbox-community/netbox

Issue:
local data source no longer working after v3.5.9 to v3.6.0 migration
### NetBox version

v.3.6.0

### Python version

3.8

### Steps to Reproduce

1. setup a local folder with a testfile on the machine running netbox
2. create a data source using that local folder
3. sync the data source and try to display content of the file

### Expected Behavior

the file and its contents displayed in gui.

### Observed Behavior

netbox runs into a server error.
<class 'TypeError'>

encoding without a string argument

![image](https://github.com/netbox-community/netbox/assets/48352307/d9da2fd1-e3a9-4b7f-bd5e-70b81a028caa)



Discussion:
It seems that the content returned by a BinaryField has changed in Django 4.2, though I'm not sure why:

```
# Django 4.1
>>> f = DataFile.objects.first()
>>> f.data
<memory at 0x7f6fbeaede40>

# Django 4.2
>>> f = DataFile.objects.first()
>>> f.data
b"I'm a test file\n"
```

Resolving patch:
diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py
--- a/netbox/core/models/data.py
+++ b/netbox/core/models/data.py
@@ -316,7 +316,7 @@ def data_as_string(self):
         if not self.data:
             return None
         try:
-            return bytes(self.data, 'utf-8')
+            return self.data.decode('utf-8')
         except UnicodeDecodeError:
             return None
 


Test patch:
Repository: netbox-community/netbox

Issue:
Uploading report without test method yields "Server Error"
### NetBox version

v3.6.0 (But reproducible in 3.6.1-dev, too)

### Python version

3.11

### Steps to Reproduce

1.Create `a.py`:
```py
from extras.reports import Report

class DeviceConnectionsReport(Report):
    description = "Validate the minimum physical connections for each device"
    pass
```
(Note, the class doesn't have a test method)

2.Upload it as report


### Expected Behavior

I expected it to either get an error, that there are no test methods in it, and the ability to delete it without using the CLI.

### Observed Behavior

Reality:
```
<class 'Exception'>

A report must contain at least one test method.

Python version: 3.11.4
NetBox version: 3.6.1-dev
Plugins: None installed
```

![image](https://github.com/netbox-community/netbox/assets/63594136/75bc3936-9ed5-4335-98cb-761829f56fc4)


Screenshot from develop branch, but reproducible with stable, too


Discussion:
I will work on this issue, if it is accepted

Resolving patch:
diff --git a/netbox/extras/reports.py b/netbox/extras/reports.py
--- a/netbox/extras/reports.py
+++ b/netbox/extras/reports.py
@@ -106,8 +106,6 @@ def __init__(self):
                     'failure': 0,
                     'log': [],
                 }
-        if not test_methods:
-            raise Exception("A report must contain at least one test method.")
         self.test_methods = test_methods
 
     @classproperty


Test patch:
Repository: netbox-community/netbox

Issue:
Cannot exit maintenance mode
### NetBox version

v3.6.0

### Python version

3.10

### Steps to Reproduce

1. Go to Current Config
2. Click on edit
3. Enable Maintenance mode
4. Go back to Current Config
5. Click on edit
6. Disable Maintenance mode

### Expected Behavior

- Netbox exits maintenance mode and functionality returned

### Observed Behavior

- Netbox stays in maintenance mode and unable to perform write operations exception occurs



Discussion:

Resolving patch:
diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py
--- a/netbox/netbox/settings.py
+++ b/netbox/netbox/settings.py
@@ -496,6 +496,7 @@ def _setting(name, default=None):
 # All URLs starting with a string listed here are exempt from maintenance mode enforcement
 MAINTENANCE_EXEMPT_PATHS = (
     f'/{BASE_PATH}admin/',
+    f'/{BASE_PATH}extras/config-revisions/',  # Allow modifying the configuration
 )
 
 SERIALIZATION_MODULES = {


Test patch:
Repository: netbox-community/netbox

Issue:
Bulk rename improperly strips "find" and "replace" fields
### NetBox version

v3.6.1

### Python version

3.11

### Steps to Reproduce

1. On an existing device, create an interface labeled something like "One Two".
2. Go to the interface tab of that device, check the checkbox next to it and hit "rename".
3. In the find field, enter "One " (note the trailing space!). In the replacement field enter "One-".
4. Click the preview button.

### Expected Behavior

NetBox should offer to rename the device to "One-Two".

### Observed Behavior

Netbox offers to rename the device to "One- Two" (note the space).

My guess (I've not looked at the code) is that this happens because django autostrips whitespace from input fields by default, and this needs to be disabled.

Also, the same bug exists on the "replace" field, and is completely analagous to the replace field.

Workaround: For the "find" field, use regex mode and \s to match trailing whitespace. For the "replace" field, I don't know of a general workaround.


Discussion:
I'm happy to volunteer to look at the code to fix this issue with a PR.

Resolving patch:
diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py
--- a/netbox/utilities/forms/forms.py
+++ b/netbox/utilities/forms/forms.py
@@ -40,8 +40,11 @@ class BulkRenameForm(BootstrapMixin, forms.Form):
     """
     An extendable form to be used for renaming objects in bulk.
     """
-    find = forms.CharField()
+    find = forms.CharField(
+        strip=False
+    )
     replace = forms.CharField(
+        strip=False,
         required=False
     )
     use_regex = forms.BooleanField(


Test patch:
diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py
--- a/netbox/utilities/tests/test_forms.py
+++ b/netbox/utilities/tests/test_forms.py
@@ -3,6 +3,7 @@
 
 from utilities.choices import ImportFormatChoices
 from utilities.forms.bulk_import import BulkImportForm
+from utilities.forms.forms import BulkRenameForm
 from utilities.forms.utils import expand_alphanumeric_pattern, expand_ipaddress_pattern
 
 
@@ -364,3 +365,16 @@ def test_csv_delimiters(self):
             {'a': '1', 'b': '2', 'c': '3'},
             {'a': '4', 'b': '5', 'c': '6'},
         ])
+
+
+class BulkRenameFormTest(TestCase):
+    def test_no_strip_whitespace(self):
+        # Tests to make sure Bulk Rename Form isn't stripping whitespaces
+        # See: https://github.com/netbox-community/netbox/issues/13791
+        form = BulkRenameForm(data={
+            "find": " hello ",
+            "replace": " world "
+        })
+        self.assertTrue(form.is_valid())
+        self.assertEqual(form.cleaned_data["find"], " hello ")
+        self.assertEqual(form.cleaned_data["replace"], " world ")
Repository: netbox-community/netbox

Issue:
Default card foreground color is the same as background
### NetBox version

v3.6.2

### Python version

3.8

### Steps to Reproduce

1. Set card's Color to Default

### Expected Behavior

A header is visible.

### Observed Behavior

![image](https://github.com/netbox-community/netbox/assets/15263497/2f5e8277-2562-4133-b31f-ad6787d51821)



Discussion:

Resolving patch:
diff --git a/netbox/extras/choices.py b/netbox/extras/choices.py
--- a/netbox/extras/choices.py
+++ b/netbox/extras/choices.py
@@ -244,3 +244,39 @@ class ChangeActionChoices(ChoiceSet):
         (ACTION_UPDATE, _('Update'), 'blue'),
         (ACTION_DELETE, _('Delete'), 'red'),
     )
+
+
+#
+# Dashboard widgets
+#
+
+class DashboardWidgetColorChoices(ChoiceSet):
+    BLUE = 'blue'
+    INDIGO = 'indigo'
+    PURPLE = 'purple'
+    PINK = 'pink'
+    RED = 'red'
+    ORANGE = 'orange'
+    YELLOW = 'yellow'
+    GREEN = 'green'
+    TEAL = 'teal'
+    CYAN = 'cyan'
+    GRAY = 'gray'
+    BLACK = 'black'
+    WHITE = 'white'
+
+    CHOICES = (
+        (BLUE, _('Blue')),
+        (INDIGO, _('Indigo')),
+        (PURPLE, _('Purple')),
+        (PINK, _('Pink')),
+        (RED, _('Red')),
+        (ORANGE, _('Orange')),
+        (YELLOW, _('Yellow')),
+        (GREEN, _('Green')),
+        (TEAL, _('Teal')),
+        (CYAN, _('Cyan')),
+        (GRAY, _('Gray')),
+        (BLACK, _('Black')),
+        (WHITE, _('White')),
+    )
diff --git a/netbox/extras/dashboard/forms.py b/netbox/extras/dashboard/forms.py
--- a/netbox/extras/dashboard/forms.py
+++ b/netbox/extras/dashboard/forms.py
@@ -2,9 +2,9 @@
 from django.urls import reverse_lazy
 from django.utils.translation import gettext as _
 
+from extras.choices import DashboardWidgetColorChoices
 from netbox.registry import registry
 from utilities.forms import BootstrapMixin, add_blank_choice
-from utilities.choices import ButtonColorChoices
 
 __all__ = (
     'DashboardWidgetAddForm',
@@ -21,7 +21,7 @@ class DashboardWidgetForm(BootstrapMixin, forms.Form):
         required=False
     )
     color = forms.ChoiceField(
-        choices=add_blank_choice(ButtonColorChoices),
+        choices=add_blank_choice(DashboardWidgetColorChoices),
         required=False,
     )
 


Test patch:
Repository: netbox-community/netbox

Issue:
Server Error when deleting no more existing Journal Entry Kind
### NetBox version

v.3.6.2

### Python version

3.10

### Steps to Reproduce

1. Go to random Location in Locations, add Journal Entry with random Kind.
2. Go to configuration.py
3. Setup 
```python
FIELD_CHOICES = {
    'extras.JournalEntry.kind': (
        ('something', 'Something', 'blue'),
    ),
}
```
4. Go again in Location where we was add Journal Entry. 
5. Try to delete Journal Entry with no more existing Kind.

### Expected Behavior

The entry should have been successfully deleted despite the fact that Kind no longer exists.

### Observed Behavior

Server Error 

```
<class 'KeyError'>

'success'

Python version: 3.10.12
NetBox version: 3.6.2
Plugins: None installed
```


Discussion:
I've updated your example configuration above to be complete.

The root cause here is the removal of the previously valid field choice. When NetBox attempts to generate a serialized copy of the journal entry (for change logging), it cannot map the raw field value to its label. This will affect any model with a configurable choice field, not just journal entries.

There's not a lot we can do in this situation, short of (somehow) preventing administrators from removing choices which have been assigned to objects. The simplest fix would be to use either the raw field value or an empty string in place of the choice label.

Resolving patch:
diff --git a/netbox/netbox/api/fields.py b/netbox/netbox/api/fields.py
--- a/netbox/netbox/api/fields.py
+++ b/netbox/netbox/api/fields.py
@@ -46,12 +46,13 @@ def validate_empty_values(self, data):
         return super().validate_empty_values(data)
 
     def to_representation(self, obj):
-        if obj == '':
-            return None
-        return {
-            'value': obj,
-            'label': self._choices[obj],
-        }
+        if obj != '':
+            # Use an empty string in place of the choice label if it cannot be resolved (i.e. because a previously
+            # configured choice has been removed from FIELD_CHOICES).
+            return {
+                'value': obj,
+                'label': self._choices.get(obj, ''),
+            }
 
     def to_internal_value(self, data):
         if data == '':


Test patch:
Repository: netbox-community/netbox

Issue:
Element search bug in custom fields.
### NetBox version

v3.6.2

### Python version

3.10

### Steps to Reproduce

1. Create a selection list for a custom field.
2. Create a custom field that can specify multiple selection lists.
3. Go to the object to which the custom field is tied.
4. Perform an edit and select the elements in the custom field.
5. With the element selected, type in the search field something that does not exist in the selection list.
6. An error message is displayed and what you have selected so far will disappear.

![image](https://github.com/netbox-community/netbox/assets/33054826/8472d03b-adbe-4f9d-a1e0-63f33d44ad3d)
![image](https://github.com/netbox-community/netbox/assets/33054826/5d021872-ce94-4581-944a-c33d42501bd5)
![image](https://github.com/netbox-community/netbox/assets/33054826/d6957da4-ee61-4314-9739-81bff3383b45)
![image](https://github.com/netbox-community/netbox/assets/33054826/4ea35a44-b1cf-4972-98ec-4fbb9d6db961)
![image](https://github.com/netbox-community/netbox/assets/33054826/238e63b3-306f-40b2-8cfa-18e9bc65667c)
![image](https://github.com/netbox-community/netbox/assets/33054826/44349afd-535b-4736-af5d-a7026bfec8dc)

PS
This is not related to the bug, but when selecting elements, is there any way to select all of them, like "ALL"? I am currently clicking on elements one at a time and was wondering if there is such a feature.



### Expected Behavior

NO Result" should appear and whatever you have selected so far should remain.

### Observed Behavior

All selections made so far have disappeared.
I can also confirm that I am seeing errors.


Discussion:
This can be triggered by making a REST API request which includes a search filter which does not match any of the available choices, e.g.

```
GET /api/extras/custom-field-choice-sets/1/choices/?q=foo
```

Resolving patch:
diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py
--- a/netbox/extras/api/views.py
+++ b/netbox/extras/api/views.py
@@ -82,7 +82,10 @@ def choices(self, request, pk):
             data = [
                 {'id': c[0], 'display': c[1]} for c in page
             ]
-            return self.get_paginated_response(data)
+        else:
+            data = []
+
+        return self.get_paginated_response(data)
 
 
 #


Test patch: