Browse Source

Fixes #19987: Show changelog_message field only for models which support change logging

Jeremy Stretch 6 months ago
parent
commit
ae425d9da9

+ 2 - 2
netbox/dcim/forms/bulk_edit.py

@@ -11,7 +11,7 @@ from ipam.choices import VLANQinQRoleChoices
 from ipam.models import ASN, VLAN, VLANGroup, VRF
 from netbox.choices import *
 from netbox.forms import NetBoxModelBulkEditForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.models import Tenant
 from users.models import User
 from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
@@ -1038,7 +1038,7 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
 # Device component templates
 #
 
-class ComponentTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ComponentTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pass
 
 

+ 2 - 2
netbox/dcim/forms/model_forms.py

@@ -11,7 +11,7 @@ from extras.models import ConfigTemplate
 from ipam.choices import VLANQinQRoleChoices
 from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VLANTranslationPolicy, VRF
 from netbox.forms import NetBoxModelForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.forms import TenancyForm
 from users.models import User
 from utilities.forms import add_blank_choice, get_field_value
@@ -974,7 +974,7 @@ class VCMemberSelectForm(forms.Form):
 # Device component templates
 #
 
-class ComponentTemplateForm(ChangeLoggingMixin, forms.ModelForm):
+class ComponentTemplateForm(ChangelogMessageMixin, forms.ModelForm):
     device_type = DynamicModelChoiceField(
         label=_('Device type'),
         queryset=DeviceType.objects.all(),

+ 11 - 11
netbox/extras/forms/bulk_edit.py

@@ -5,7 +5,7 @@ from extras.choices import *
 from extras.models import *
 from netbox.events import get_event_type_choices
 from netbox.forms import NetBoxModelBulkEditForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from utilities.forms import BulkEditForm, add_blank_choice
 from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField
 from utilities.forms.rendering import FieldSet
@@ -28,7 +28,7 @@ __all__ = (
 )
 
 
-class CustomFieldBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomField.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -96,7 +96,7 @@ class CustomFieldBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('group_name', 'description', 'choice_set')
 
 
-class CustomFieldChoiceSetBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomFieldChoiceSet.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -116,7 +116,7 @@ class CustomFieldChoiceSetBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('base_choices', 'description')
 
 
-class CustomLinkBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomLink.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -142,7 +142,7 @@ class CustomLinkBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     )
 
 
-class ExportTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=ExportTemplate.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -175,7 +175,7 @@ class ExportTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
 
 
-class SavedFilterBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class SavedFilterBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=SavedFilter.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -295,7 +295,7 @@ class EventRuleBulkEditForm(NetBoxModelBulkEditForm):
     nullable_fields = ('description', 'conditions')
 
 
-class TagBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -317,7 +317,7 @@ class TagBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description',)
 
 
-class ConfigContextBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=ConfigContext.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -341,7 +341,7 @@ class ConfigContextBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description',)
 
 
-class ConfigTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ConfigTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=ConfigTemplate.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -374,7 +374,7 @@ class ConfigTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
 
 
-class JournalEntryBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class JournalEntryBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=JournalEntry.objects.all(),
         widget=forms.MultipleHiddenInput
@@ -387,7 +387,7 @@ class JournalEntryBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     comments = CommentField()
 
 
-class NotificationGroupBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class NotificationGroupBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=NotificationGroup.objects.all(),
         widget=forms.MultipleHiddenInput

+ 10 - 10
netbox/extras/forms/model_forms.py

@@ -13,7 +13,7 @@ from extras.choices import *
 from extras.models import *
 from netbox.events import get_event_type_choices
 from netbox.forms import NetBoxModelForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.models import Tenant, TenantGroup
 from users.models import Group, User
 from utilities.forms import get_field_value
@@ -46,7 +46,7 @@ __all__ = (
 )
 
 
-class CustomFieldForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -165,7 +165,7 @@ class CustomFieldForm(ChangeLoggingMixin, forms.ModelForm):
             del self.fields['choice_set']
 
 
-class CustomFieldChoiceSetForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
     # TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model
     extra_choices = forms.CharField(
         widget=ChoicesWidget(),
@@ -218,7 +218,7 @@ class CustomFieldChoiceSetForm(ChangeLoggingMixin, forms.ModelForm):
         return data
 
 
-class CustomLinkForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('custom_links')
@@ -250,7 +250,7 @@ class CustomLinkForm(ChangeLoggingMixin, forms.ModelForm):
         }
 
 
-class ExportTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('export_templates')
@@ -292,7 +292,7 @@ class ExportTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
         return self.cleaned_data
 
 
-class SavedFilterForm(ChangeLoggingMixin, forms.ModelForm):
+class SavedFilterForm(ChangelogMessageMixin, forms.ModelForm):
     slug = SlugField()
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
@@ -389,7 +389,7 @@ class BookmarkForm(forms.ModelForm):
         fields = ('object_type', 'object_id')
 
 
-class NotificationGroupForm(ChangeLoggingMixin, forms.ModelForm):
+class NotificationGroupForm(ChangelogMessageMixin, forms.ModelForm):
     groups = DynamicModelMultipleChoiceField(
         label=_('Groups'),
         required=False,
@@ -562,7 +562,7 @@ class EventRuleForm(NetBoxModelForm):
         return self.cleaned_data
 
 
-class TagForm(ChangeLoggingMixin, forms.ModelForm):
+class TagForm(ChangelogMessageMixin, forms.ModelForm):
     slug = SlugField()
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
@@ -585,7 +585,7 @@ class TagForm(ChangeLoggingMixin, forms.ModelForm):
         ]
 
 
-class ConfigContextForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     regions = DynamicModelMultipleChoiceField(
         label=_('Regions'),
         queryset=Region.objects.all(),
@@ -697,7 +697,7 @@ class ConfigContextForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
         return self.cleaned_data
 
 
-class ConfigTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     tags = DynamicModelMultipleChoiceField(
         label=_('Tags'),
         queryset=Tag.objects.all(),

+ 3 - 3
netbox/netbox/forms/base.py

@@ -11,7 +11,7 @@ from extras.models import CustomField, Tag
 from utilities.forms import BulkEditForm, CSVModelForm
 from utilities.forms.fields import CSVModelMultipleChoiceField, DynamicModelMultipleChoiceField
 from utilities.forms.mixins import CheckLastUpdatedMixin
-from .mixins import ChangeLoggingMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin
+from .mixins import ChangelogMessageMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin
 
 __all__ = (
     'NetBoxModelForm',
@@ -21,7 +21,7 @@ __all__ = (
 )
 
 
-class NetBoxModelForm(ChangeLoggingMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm):
+class NetBoxModelForm(ChangelogMessageMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm):
     """
     Base form for creating & editing NetBox models. Extends Django's ModelForm to add support for custom fields.
 
@@ -100,7 +100,7 @@ class NetBoxModelImportForm(CSVModelForm, NetBoxModelForm):
         return customfield.to_form_field(for_csv_import=True)
 
 
-class NetBoxModelBulkEditForm(ChangeLoggingMixin, CustomFieldsMixin, BulkEditForm):
+class NetBoxModelBulkEditForm(ChangelogMessageMixin, CustomFieldsMixin, BulkEditForm):
     """
     Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
     fields and adding/removing tags.

+ 2 - 2
netbox/netbox/forms/mixins.py

@@ -7,14 +7,14 @@ from extras.models import *
 from utilities.forms.fields import DynamicModelMultipleChoiceField
 
 __all__ = (
-    'ChangeLoggingMixin',
+    'ChangelogMessageMixin',
     'CustomFieldsMixin',
     'SavedFiltersMixin',
     'TagsMixin',
 )
 
 
-class ChangeLoggingMixin(forms.Form):
+class ChangelogMessageMixin(forms.Form):
     """
     Adds an optional field for recording a message on the resulting changelog record(s).
     """

+ 3 - 16
netbox/netbox/views/generic/bulk_views.py

@@ -21,14 +21,12 @@ from core.models import ObjectType
 from core.signals import clear_events
 from extras.choices import CustomFieldUIEditableChoices
 from extras.models import CustomField, ExportTemplate
-from netbox.forms.mixins import ChangeLoggingMixin
 from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename
 from utilities.error_handlers import handle_protectederror
 from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
 from utilities.export import TableExport
-from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
+from utilities.forms import BulkDeleteForm, BulkRenameForm, restrict_form_fields
 from utilities.forms.bulk_import import BulkImportForm
-from utilities.forms.mixins import BackgroundJobMixin
 from utilities.htmx import htmx_partial
 from utilities.jobs import AsyncJobData, is_background_request, process_request_as_job
 from utilities.permissions import get_permission_for_model
@@ -896,15 +894,6 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
     def get_required_permission(self):
         return get_permission_for_model(self.queryset.model, 'delete')
 
-    def get_form(self):
-        """
-        Provide a standard bulk delete form if none has been specified for the view
-        """
-        class BulkDeleteForm(BackgroundJobMixin, ChangeLoggingMixin, ConfirmationForm):
-            pk = ModelMultipleChoiceField(queryset=self.queryset, widget=MultipleHiddenInput)
-
-        return BulkDeleteForm
-
     #
     # Request handlers
     #
@@ -925,10 +914,8 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
         else:
             pk_list = [int(pk) for pk in request.POST.getlist('pk')]
 
-        form_cls = self.get_form()
-
         if '_confirm' in request.POST:
-            form = form_cls(request.POST)
+            form = BulkDeleteForm(model, request.POST)
             if form.is_valid():
                 logger.debug("Form validation was successful")
 
@@ -990,7 +977,7 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
                 logger.debug("Form validation failed")
 
         else:
-            form = form_cls(initial={
+            form = BulkDeleteForm(model, initial={
                 'pk': pk_list,
                 'return_url': self.get_return_url(request),
             })

+ 2 - 2
netbox/netbox/views/generic/object_views.py

@@ -425,7 +425,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
             request: The current request
         """
         obj = self.get_object(**kwargs)
-        form = DeleteForm(initial=request.GET)
+        form = DeleteForm(instance=obj, initial=request.GET)
 
         try:
             dependent_objects = self._get_dependent_objects(obj)
@@ -464,7 +464,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
         """
         logger = logging.getLogger('netbox.views.ObjectDeleteView')
         obj = self.get_object(**kwargs)
-        form = DeleteForm(request.POST)
+        form = DeleteForm(request.POST, instance=obj)
 
         if form.is_valid():
             logger.debug("Form validation was successful")

+ 2 - 2
netbox/utilities/forms/bulk_import.py

@@ -8,13 +8,13 @@ from django.utils.translation import gettext as _
 
 from core.forms.mixins import SyncedDataMixin
 from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, ImportMethodChoices
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from utilities.constants import CSV_DELIMITERS
 from utilities.forms.mixins import BackgroundJobMixin
 from utilities.forms.utils import parse_csv
 
 
-class BulkImportForm(ChangeLoggingMixin, BackgroundJobMixin, SyncedDataMixin, forms.Form):
+class BulkImportForm(ChangelogMessageMixin, BackgroundJobMixin, SyncedDataMixin, forms.Form):
     import_method = forms.ChoiceField(
         choices=ImportMethodChoices,
         required=False

+ 29 - 0
netbox/utilities/forms/forms.py

@@ -3,9 +3,11 @@ import re
 from django import forms
 from django.utils.translation import gettext as _
 
+from netbox.models.features import ChangeLoggingMixin
 from utilities.forms.mixins import BackgroundJobMixin
 
 __all__ = (
+    'BulkDeleteForm',
     'BulkEditForm',
     'BulkRenameForm',
     'ConfirmationForm',
@@ -40,6 +42,13 @@ class DeleteForm(ConfirmationForm):
         max_length=200
     )
 
+    def __init__(self, *args, instance=None, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # Hide the changelog_message filed if the model doesn't support change logging
+        if instance is None or not issubclass(instance._meta.model, ChangeLoggingMixin):
+            self.fields.pop('changelog_message')
+
 
 class BulkEditForm(BackgroundJobMixin, forms.Form):
     """
@@ -81,6 +90,26 @@ class BulkRenameForm(forms.Form):
                 })
 
 
+class BulkDeleteForm(BackgroundJobMixin, ConfirmationForm):
+    pk = forms.ModelMultipleChoiceField(
+        queryset=None,
+        widget=forms.MultipleHiddenInput
+    )
+    changelog_message = forms.CharField(
+        required=False,
+        max_length=200
+    )
+
+    def __init__(self, model, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        self.fields['pk'].queryset = model.objects.all()
+
+        # Hide the changelog_message filed if the model doesn't support change logging
+        if model is None or not issubclass(model, ChangeLoggingMixin):
+            self.fields.pop('changelog_message')
+
+
 class CSVModelForm(forms.ModelForm):
     """
     ModelForm used for the import of objects in CSV format.