Closes #20304: Object owners (#20634)
CI / build (20.x, 3.12) (push) Has been cancelled
CI / build (20.x, 3.13) (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

This commit is contained in:
Jeremy Stretch
2025-10-24 16:08:01 -04:00
committed by GitHub
parent 52d4498caf
commit be74436884
196 changed files with 15831 additions and 2715 deletions
@@ -8,7 +8,8 @@ from dcim.api.serializers_.sites import LocationSerializer, RegionSerializer, Si
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from extras.models import ConfigContext, ConfigContextProfile, Tag
from netbox.api.fields import SerializedPKRelatedField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from netbox.api.serializers import ChangeLogMessageSerializer, PrimaryModelSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from tenancy.api.serializers_.tenants import TenantSerializer, TenantGroupSerializer
from tenancy.models import Tenant, TenantGroup
from virtualization.api.serializers_.clusters import ClusterSerializer, ClusterGroupSerializer, ClusterTypeSerializer
@@ -20,13 +21,7 @@ __all__ = (
)
class ConfigContextProfileSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
tags = serializers.SlugRelatedField(
queryset=Tag.objects.all(),
slug_field='slug',
required=False,
many=True
)
class ConfigContextProfileSerializer(PrimaryModelSerializer):
data_source = DataSourceSerializer(
nested=True,
required=False
@@ -39,13 +34,13 @@ class ConfigContextProfileSerializer(ChangeLogMessageSerializer, ValidatedModelS
class Meta:
model = ConfigContextProfile
fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'tags', 'comments', 'data_source',
'data_path', 'data_file', 'data_synced', 'created', 'last_updated',
'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'tags', 'owner', 'comments',
'data_source', 'data_path', 'data_file', 'data_synced', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
class ConfigContextSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class ConfigContextSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
profile = ConfigContextProfileSerializer(
nested=True,
required=False,
@@ -156,7 +151,7 @@ class ConfigContextSerializer(ChangeLogMessageSerializer, ValidatedModelSerializ
fields = [
'id', 'url', 'display_url', 'display', 'name', 'weight', 'profile', 'description', 'is_active', 'regions',
'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types',
'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data_source', 'data_path', 'data_file',
'data_synced', 'data', 'created', 'last_updated',
'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'owner', 'tags', 'data_source', 'data_path',
'data_file', 'data_synced', 'data', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -2,13 +2,19 @@ from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer
from extras.models import ConfigTemplate
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from netbox.api.serializers.features import TaggableModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'ConfigTemplateSerializer',
)
class ConfigTemplateSerializer(ChangeLogMessageSerializer, TaggableModelSerializer, ValidatedModelSerializer):
class ConfigTemplateSerializer(
OwnerMixin,
ChangeLogMessageSerializer,
TaggableModelSerializer,
ValidatedModelSerializer
):
data_source = DataSourceSerializer(
nested=True,
required=False
@@ -23,6 +29,6 @@ class ConfigTemplateSerializer(ChangeLogMessageSerializer, TaggableModelSerializ
fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'environment_params', 'template_code',
'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file',
'data_synced', 'tags', 'created', 'last_updated',
'data_synced', 'owner', 'tags', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -8,6 +8,7 @@ from extras.choices import *
from extras.models import CustomField, CustomFieldChoiceSet
from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'CustomFieldChoiceSetSerializer',
@@ -15,7 +16,7 @@ __all__ = (
)
class CustomFieldChoiceSetSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class CustomFieldChoiceSetSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
base_choices = ChoiceField(
choices=CustomFieldChoiceSetBaseChoices,
required=False
@@ -32,12 +33,12 @@ class CustomFieldChoiceSetSerializer(ChangeLogMessageSerializer, ValidatedModelS
model = CustomFieldChoiceSet
fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'base_choices', 'extra_choices',
'order_alphabetically', 'choices_count', 'created', 'last_updated',
'order_alphabetically', 'choices_count', 'owner', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
class CustomFieldSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class CustomFieldSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('custom_fields'),
many=True
@@ -64,8 +65,8 @@ class CustomFieldSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer
'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type',
'name', 'label', 'group_name', 'description', 'required', 'unique', 'search_weight', 'filter_logic',
'ui_visible', 'ui_editable', 'is_cloneable', 'default', 'related_object_filter', 'weight',
'validation_minimum', 'validation_maximum', 'validation_regex', 'choice_set', 'comments', 'created',
'last_updated',
'validation_minimum', 'validation_maximum', 'validation_regex', 'choice_set', 'owner', 'comments',
'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -2,13 +2,14 @@ from core.models import ObjectType
from extras.models import CustomLink
from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'CustomLinkSerializer',
)
class CustomLinkSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class CustomLinkSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('custom_links'),
many=True
@@ -18,6 +19,6 @@ class CustomLinkSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer)
model = CustomLink
fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'link_text', 'link_url',
'weight', 'group_name', 'button_class', 'new_window', 'created', 'last_updated',
'weight', 'group_name', 'button_class', 'new_window', 'owner', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name')
+5 -4
View File
@@ -7,6 +7,7 @@ from extras.choices import *
from extras.models import EventRule, Webhook
from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from utilities.api import get_serializer_for_model
from .scripts import ScriptSerializer
@@ -20,7 +21,7 @@ __all__ = (
# Event Rules
#
class EventRuleSerializer(NetBoxModelSerializer):
class EventRuleSerializer(OwnerMixin, NetBoxModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('event_rules'),
many=True
@@ -36,7 +37,7 @@ class EventRuleSerializer(NetBoxModelSerializer):
fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'event_types', 'conditions',
'action_type', 'action_object_type', 'action_object_id', 'action_object', 'description', 'custom_fields',
'tags', 'created', 'last_updated',
'owner', 'tags', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -56,13 +57,13 @@ class EventRuleSerializer(NetBoxModelSerializer):
# Webhooks
#
class WebhookSerializer(NetBoxModelSerializer):
class WebhookSerializer(OwnerMixin, NetBoxModelSerializer):
class Meta:
model = Webhook
fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'payload_url', 'http_method',
'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path',
'custom_fields', 'tags', 'created', 'last_updated',
'custom_fields', 'owner', 'tags', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -3,13 +3,14 @@ from core.models import ObjectType
from extras.models import ExportTemplate
from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'ExportTemplateSerializer',
)
class ExportTemplateSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class ExportTemplateSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('export_templates'),
many=True
@@ -28,6 +29,6 @@ class ExportTemplateSerializer(ChangeLogMessageSerializer, ValidatedModelSeriali
fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'environment_params',
'template_code', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source',
'data_path', 'data_file', 'data_synced', 'created', 'last_updated',
'data_path', 'data_file', 'data_synced', 'owner', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -2,13 +2,14 @@ from core.models import ObjectType
from extras.models import SavedFilter
from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'SavedFilterSerializer',
)
class SavedFilterSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class SavedFilterSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.all(),
many=True
@@ -18,6 +19,6 @@ class SavedFilterSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer
model = SavedFilter
fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'slug', 'description', 'user', 'weight',
'enabled', 'shared', 'parameters', 'created', 'last_updated',
'enabled', 'shared', 'parameters', 'owner', 'created', 'last_updated',
]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')
+2 -1
View File
@@ -6,6 +6,7 @@ from extras.models import Tag, TaggedItem
from netbox.api.exceptions import SerializerNotFound
from netbox.api.fields import ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import BaseModelSerializer, ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from utilities.api import get_serializer_for_model
__all__ = (
@@ -14,7 +15,7 @@ __all__ = (
)
class TagSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer):
class TagSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('tags'),
many=True,
+13 -12
View File
@@ -5,8 +5,9 @@ from django.utils.translation import gettext as _
from core.models import DataSource, ObjectType
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet
from tenancy.models import Tenant, TenantGroup
from users.filterset_mixins import OwnerFilterMixin
from users.models import Group, User
from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
@@ -61,7 +62,7 @@ class ScriptFilterSet(BaseFilterSet):
)
class WebhookFilterSet(NetBoxModelFilterSet):
class WebhookFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -90,7 +91,7 @@ class WebhookFilterSet(NetBoxModelFilterSet):
)
class EventRuleFilterSet(NetBoxModelFilterSet):
class EventRuleFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -130,7 +131,7 @@ class EventRuleFilterSet(NetBoxModelFilterSet):
return queryset.filter(event_types__overlap=value)
class CustomFieldFilterSet(ChangeLoggedModelFilterSet):
class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -179,7 +180,7 @@ class CustomFieldFilterSet(ChangeLoggedModelFilterSet):
)
class CustomFieldChoiceSetFilterSet(ChangeLoggedModelFilterSet):
class CustomFieldChoiceSetFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -207,7 +208,7 @@ class CustomFieldChoiceSetFilterSet(ChangeLoggedModelFilterSet):
return queryset.filter(extra_choices__overlap=value)
class CustomLinkFilterSet(ChangeLoggedModelFilterSet):
class CustomLinkFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -237,7 +238,7 @@ class CustomLinkFilterSet(ChangeLoggedModelFilterSet):
)
class ExportTemplateFilterSet(ChangeLoggedModelFilterSet):
class ExportTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -275,7 +276,7 @@ class ExportTemplateFilterSet(ChangeLoggedModelFilterSet):
)
class SavedFilterFilterSet(ChangeLoggedModelFilterSet):
class SavedFilterFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -494,7 +495,7 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
return queryset.filter(comments__icontains=value)
class TagFilterSet(ChangeLoggedModelFilterSet):
class TagFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -589,7 +590,7 @@ class TaggedItemFilterSet(BaseFilterSet):
)
class ConfigContextProfileFilterSet(NetBoxModelFilterSet):
class ConfigContextProfileFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -619,7 +620,7 @@ class ConfigContextProfileFilterSet(NetBoxModelFilterSet):
)
class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
@@ -788,7 +789,7 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
)
class ConfigTemplateFilterSet(ChangeLoggedModelFilterSet):
class ConfigTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
+13 -19
View File
@@ -4,8 +4,8 @@ from django.utils.translation import gettext_lazy as _
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 ChangelogMessageMixin
from netbox.forms import NetBoxModelBulkEditForm, PrimaryModelBulkEditForm
from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from utilities.forms import BulkEditForm, add_blank_choice
from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField
from utilities.forms.rendering import FieldSet
@@ -30,7 +30,7 @@ __all__ = (
)
class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class CustomFieldBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=CustomField.objects.all(),
widget=forms.MultipleHiddenInput
@@ -98,7 +98,7 @@ class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('group_name', 'description', 'choice_set')
class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=CustomFieldChoiceSet.objects.all(),
widget=forms.MultipleHiddenInput
@@ -118,7 +118,7 @@ class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('base_choices', 'description')
class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class CustomLinkBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=CustomLink.objects.all(),
widget=forms.MultipleHiddenInput
@@ -144,7 +144,7 @@ class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm):
)
class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class ExportTemplateBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=ExportTemplate.objects.all(),
widget=forms.MultipleHiddenInput
@@ -177,7 +177,7 @@ class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
class SavedFilterBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class SavedFilterBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=SavedFilter.objects.all(),
widget=forms.MultipleHiddenInput
@@ -233,7 +233,7 @@ class TableConfigBulkEditForm(BulkEditForm):
nullable_fields = ('description',)
class WebhookBulkEditForm(NetBoxModelBulkEditForm):
class WebhookBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
model = Webhook
pk = forms.ModelMultipleChoiceField(
@@ -271,7 +271,7 @@ class WebhookBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('secret', 'ca_file_path')
class EventRuleBulkEditForm(NetBoxModelBulkEditForm):
class EventRuleBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
model = EventRule
pk = forms.ModelMultipleChoiceField(
@@ -297,7 +297,7 @@ class EventRuleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description', 'conditions')
class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class TagBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=Tag.objects.all(),
widget=forms.MultipleHiddenInput
@@ -319,17 +319,11 @@ class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('description',)
class ConfigContextProfileBulkEditForm(NetBoxModelBulkEditForm):
class ConfigContextProfileBulkEditForm(PrimaryModelBulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=ConfigContextProfile.objects.all(),
widget=forms.MultipleHiddenInput
)
description = forms.CharField(
label=_('Description'),
required=False,
max_length=100
)
comments = CommentField()
model = ConfigContextProfile
fieldsets = (
@@ -338,7 +332,7 @@ class ConfigContextProfileBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description',)
class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class ConfigContextBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=ConfigContext.objects.all(),
widget=forms.MultipleHiddenInput
@@ -369,7 +363,7 @@ class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('profile', 'description')
class ConfigTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
class ConfigTemplateBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=ConfigTemplate.objects.all(),
widget=forms.MultipleHiddenInput
+21 -21
View File
@@ -9,7 +9,7 @@ from core.models import ObjectType
from extras.choices import *
from extras.models import *
from netbox.events import get_event_type_choices
from netbox.forms import NetBoxModelImportForm
from netbox.forms import NetBoxModelImportForm, OwnerCSVMixin, PrimaryModelImportForm
from users.models import Group, User
from utilities.forms import CSVModelForm
from utilities.forms.fields import (
@@ -33,7 +33,7 @@ __all__ = (
)
class CustomFieldImportForm(CSVModelForm):
class CustomFieldImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -75,11 +75,11 @@ class CustomFieldImportForm(CSVModelForm):
fields = (
'name', 'label', 'group_name', 'type', 'object_types', 'related_object_type', 'required', 'unique',
'description', 'search_weight', 'filter_logic', 'default', 'choice_set', 'weight', 'validation_minimum',
'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable', 'comments',
'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable', 'owner', 'comments',
)
class CustomFieldChoiceSetImportForm(CSVModelForm):
class CustomFieldChoiceSetImportForm(OwnerCSVMixin, CSVModelForm):
base_choices = CSVChoiceField(
choices=CustomFieldChoiceSetBaseChoices,
required=False,
@@ -97,7 +97,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
class Meta:
model = CustomFieldChoiceSet
fields = (
'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner',
)
def clean_extra_choices(self):
@@ -114,7 +114,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
return data
class CustomLinkImportForm(CSVModelForm):
class CustomLinkImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_links'),
@@ -131,11 +131,11 @@ class CustomLinkImportForm(CSVModelForm):
model = CustomLink
fields = (
'name', 'object_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text',
'link_url',
'link_url', 'owner',
)
class ExportTemplateImportForm(CSVModelForm):
class ExportTemplateImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates'),
@@ -146,30 +146,30 @@ class ExportTemplateImportForm(CSVModelForm):
model = ExportTemplate
fields = (
'name', 'object_types', 'description', 'environment_params', 'mime_type', 'file_name', 'file_extension',
'as_attachment', 'template_code',
'as_attachment', 'template_code', 'owner',
)
class ConfigContextProfileImportForm(NetBoxModelImportForm):
class ConfigContextProfileImportForm(PrimaryModelImportForm):
class Meta:
model = ConfigContextProfile
fields = [
'name', 'description', 'schema', 'comments', 'tags',
'name', 'description', 'schema', 'owner', 'comments', 'tags',
]
class ConfigTemplateImportForm(CSVModelForm):
class ConfigTemplateImportForm(OwnerCSVMixin, CSVModelForm):
class Meta:
model = ConfigTemplate
fields = (
'name', 'description', 'template_code', 'environment_params', 'mime_type', 'file_name', 'file_extension',
'as_attachment', 'tags',
'as_attachment', 'owner', 'tags',
)
class SavedFilterImportForm(CSVModelForm):
class SavedFilterImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField(
label=_('Object types'),
queryset=ObjectType.objects.all(),
@@ -179,21 +179,21 @@ class SavedFilterImportForm(CSVModelForm):
class Meta:
model = SavedFilter
fields = (
'name', 'slug', 'object_types', 'description', 'weight', 'enabled', 'shared', 'parameters',
'name', 'slug', 'object_types', 'description', 'weight', 'enabled', 'shared', 'parameters', 'owner',
)
class WebhookImportForm(NetBoxModelImportForm):
class WebhookImportForm(OwnerCSVMixin, NetBoxModelImportForm):
class Meta:
model = Webhook
fields = (
'name', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template',
'secret', 'ssl_verification', 'ca_file_path', 'description', 'tags'
'secret', 'ssl_verification', 'ca_file_path', 'description', 'owner', 'tags'
)
class EventRuleImportForm(NetBoxModelImportForm):
class EventRuleImportForm(OwnerCSVMixin, NetBoxModelImportForm):
object_types = CSVMultipleContentTypeField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('event_rules'),
@@ -214,7 +214,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
model = EventRule
fields = (
'name', 'description', 'enabled', 'conditions', 'object_types', 'event_types', 'action_type',
'comments', 'tags'
'owner', 'comments', 'tags'
)
def clean(self):
@@ -242,7 +242,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
self.instance.action_object_type = ObjectType.objects.get_for_model(script, for_concrete_model=False)
class TagImportForm(CSVModelForm):
class TagImportForm(OwnerCSVMixin, CSVModelForm):
slug = SlugField()
weight = forms.IntegerField(
label=_('Weight'),
@@ -258,7 +258,7 @@ class TagImportForm(CSVModelForm):
class Meta:
model = Tag
fields = (
'name', 'slug', 'color', 'weight', 'description', 'object_types',
'name', 'slug', 'color', 'weight', 'description', 'object_types', 'owner',
)
+58 -8
View File
@@ -6,13 +6,14 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site
from extras.choices import *
from extras.models import *
from netbox.events import get_event_type_choices
from netbox.forms.base import NetBoxModelFilterSetForm
from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
from netbox.forms.mixins import SavedFiltersMixin
from tenancy.models import Tenant, TenantGroup
from users.models import Group, User
from users.models import Group, Owner, User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import (
ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField,
ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
TagFilterField,
)
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import DateTimePicker
@@ -115,6 +116,11 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
label=_('Validation regex'),
required=False
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
@@ -130,6 +136,11 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
choice = forms.CharField(
required=False
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
@@ -161,6 +172,11 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'),
required=False
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
@@ -207,6 +223,11 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
@@ -255,6 +276,11 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'),
required=False
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
@@ -290,7 +316,7 @@ class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
class WebhookFilterForm(NetBoxModelFilterSetForm):
model = Webhook
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')),
)
http_content_type = forms.CharField(
@@ -306,15 +332,18 @@ class WebhookFilterForm(NetBoxModelFilterSetForm):
required=False,
label=_('HTTP method')
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
tag = TagFilterField(model)
class EventRuleFilterForm(NetBoxModelFilterSetForm):
model = EventRule
tag = TagFilterField(model)
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')),
)
object_type_id = ContentTypeMultipleChoiceField(
@@ -339,6 +368,12 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
tag = TagFilterField(model)
class TagFilterForm(SavedFiltersMixin, FilterForm):
@@ -353,9 +388,14 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
required=False,
label=_('Allowed object type')
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ConfigContextProfileFilterForm(SavedFiltersMixin, FilterForm):
class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
model = ConfigContextProfile
fieldsets = (
FieldSet('q', 'filter_id'),
@@ -470,6 +510,11 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
required=False,
label=_('Tags')
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
@@ -512,6 +557,11 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class LocalConfigContextFilterForm(forms.Form):
+19 -18
View File
@@ -12,8 +12,8 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site
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 ChangelogMessageMixin
from netbox.forms import NetBoxModelForm, PrimaryModelForm
from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from tenancy.models import Tenant, TenantGroup
from users.models import Group, User
from utilities.forms import get_field_value
@@ -47,7 +47,7 @@ __all__ = (
)
class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm):
class CustomFieldForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -166,7 +166,7 @@ class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm):
del self.fields['choice_set']
class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
class CustomFieldChoiceSetForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
# TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model
extra_choices = forms.CharField(
widget=ChoicesWidget(),
@@ -179,7 +179,7 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
class Meta:
model = CustomFieldChoiceSet
fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically')
fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner')
def __init__(self, *args, initial=None, **kwargs):
super().__init__(*args, initial=initial, **kwargs)
@@ -219,7 +219,7 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
return data
class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm):
class CustomLinkForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_links')
@@ -251,7 +251,7 @@ class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm):
}
class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates')
@@ -293,7 +293,7 @@ class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm
return self.cleaned_data
class SavedFilterForm(ChangelogMessageMixin, forms.ModelForm):
class SavedFilterForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
slug = SlugField()
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
@@ -427,7 +427,7 @@ class SubscriptionForm(forms.ModelForm):
fields = ('object_type', 'object_id')
class WebhookForm(NetBoxModelForm):
class WebhookForm(OwnerMixin, NetBoxModelForm):
fieldsets = (
FieldSet('name', 'description', 'tags', name=_('Webhook')),
@@ -447,7 +447,7 @@ class WebhookForm(NetBoxModelForm):
}
class EventRuleForm(NetBoxModelForm):
class EventRuleForm(OwnerMixin, NetBoxModelForm):
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
queryset=ObjectType.objects.with_feature('event_rules'),
@@ -480,7 +480,7 @@ class EventRuleForm(NetBoxModelForm):
model = EventRule
fields = (
'object_types', 'name', 'description', 'enabled', 'event_types', 'conditions', 'action_type',
'action_object_type', 'action_object_id', 'action_data', 'comments', 'tags'
'action_object_type', 'action_object_id', 'action_data', 'owner', 'comments', 'tags'
)
widgets = {
'conditions': forms.Textarea(attrs={'class': 'font-monospace'}),
@@ -563,7 +563,7 @@ class EventRuleForm(NetBoxModelForm):
return self.cleaned_data
class TagForm(ChangelogMessageMixin, forms.ModelForm):
class TagForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
slug = SlugField()
object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
@@ -582,11 +582,11 @@ class TagForm(ChangelogMessageMixin, forms.ModelForm):
class Meta:
model = Tag
fields = [
'name', 'slug', 'color', 'weight', 'description', 'object_types',
'name', 'slug', 'color', 'weight', 'description', 'object_types', 'owner',
]
class ConfigContextProfileForm(SyncedDataMixin, NetBoxModelForm):
class ConfigContextProfileForm(SyncedDataMixin, PrimaryModelForm):
schema = JSONField(
label=_('Schema'),
required=False,
@@ -606,11 +606,12 @@ class ConfigContextProfileForm(SyncedDataMixin, NetBoxModelForm):
class Meta:
model = ConfigContextProfile
fields = (
'name', 'description', 'schema', 'data_source', 'data_file', 'auto_sync_enabled', 'comments', 'tags',
'name', 'description', 'schema', 'data_source', 'data_file', 'auto_sync_enabled', 'owner', 'comments',
'tags',
)
class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
profile = DynamicModelChoiceField(
label=_('Profile'),
queryset=ConfigContextProfile.objects.all(),
@@ -701,7 +702,7 @@ class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm)
fields = (
'name', 'weight', 'profile', 'description', 'data', 'is_active', 'regions', 'site_groups', 'sites',
'locations', 'roles', 'device_types', 'platforms', 'cluster_types', 'cluster_groups', 'clusters',
'tenant_groups', 'tenants', 'tags', 'data_source', 'data_file', 'auto_sync_enabled',
'tenant_groups', 'tenants', 'owner', 'tags', 'data_source', 'data_file', 'auto_sync_enabled',
)
def __init__(self, *args, initial=None, **kwargs):
@@ -727,7 +728,7 @@ class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm)
return self.cleaned_data
class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
tags = DynamicModelMultipleChoiceField(
label=_('Tags'),
queryset=Tag.objects.all(),
+13 -12
View File
@@ -6,7 +6,8 @@ import strawberry_django
from core.graphql.mixins import SyncedDataMixin
from extras import models
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
from netbox.graphql.types import BaseObjectType, ContentTypeType, NetBoxObjectType, ObjectType, OrganizationalObjectType
from netbox.graphql.types import BaseObjectType, ContentTypeType, ObjectType, PrimaryObjectType
from users.graphql.mixins import OwnerMixin
from .filters import *
if TYPE_CHECKING:
@@ -51,7 +52,7 @@ __all__ = (
filters=ConfigContextProfileFilter,
pagination=True
)
class ConfigContextProfileType(SyncedDataMixin, NetBoxObjectType):
class ConfigContextProfileType(SyncedDataMixin, PrimaryObjectType):
pass
@@ -61,7 +62,7 @@ class ConfigContextProfileType(SyncedDataMixin, NetBoxObjectType):
filters=ConfigContextFilter,
pagination=True
)
class ConfigContextType(SyncedDataMixin, ObjectType):
class ConfigContextType(SyncedDataMixin, OwnerMixin, ObjectType):
profile: ConfigContextProfileType | None
roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]]
device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]]
@@ -84,7 +85,7 @@ class ConfigContextType(SyncedDataMixin, ObjectType):
filters=ConfigTemplateFilter,
pagination=True
)
class ConfigTemplateType(SyncedDataMixin, TagsMixin, ObjectType):
class ConfigTemplateType(SyncedDataMixin, OwnerMixin, TagsMixin, ObjectType):
virtualmachines: List[Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]]
devices: List[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]]
platforms: List[Annotated["PlatformType", strawberry.lazy('dcim.graphql.types')]]
@@ -97,7 +98,7 @@ class ConfigTemplateType(SyncedDataMixin, TagsMixin, ObjectType):
filters=CustomFieldFilter,
pagination=True
)
class CustomFieldType(ObjectType):
class CustomFieldType(OwnerMixin, ObjectType):
related_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None
choice_set: Annotated["CustomFieldChoiceSetType", strawberry.lazy('extras.graphql.types')] | None
@@ -108,7 +109,7 @@ class CustomFieldType(ObjectType):
filters=CustomFieldChoiceSetFilter,
pagination=True
)
class CustomFieldChoiceSetType(ObjectType):
class CustomFieldChoiceSetType(OwnerMixin, ObjectType):
choices_for: List[Annotated["CustomFieldType", strawberry.lazy('extras.graphql.types')]]
extra_choices: List[List[str]] | None
@@ -120,7 +121,7 @@ class CustomFieldChoiceSetType(ObjectType):
filters=CustomLinkFilter,
pagination=True
)
class CustomLinkType(ObjectType):
class CustomLinkType(OwnerMixin, ObjectType):
pass
@@ -130,7 +131,7 @@ class CustomLinkType(ObjectType):
filters=ExportTemplateFilter,
pagination=True
)
class ExportTemplateType(SyncedDataMixin, ObjectType):
class ExportTemplateType(SyncedDataMixin, OwnerMixin, ObjectType):
pass
@@ -180,7 +181,7 @@ class NotificationGroupType(ObjectType):
filters=SavedFilterFilter,
pagination=True
)
class SavedFilterType(ObjectType):
class SavedFilterType(OwnerMixin, ObjectType):
user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None
@@ -209,7 +210,7 @@ class TableConfigType(ObjectType):
filters=TagFilter,
pagination=True
)
class TagType(ObjectType):
class TagType(OwnerMixin, ObjectType):
color: str
object_types: List[ContentTypeType]
@@ -221,7 +222,7 @@ class TagType(ObjectType):
filters=WebhookFilter,
pagination=True
)
class WebhookType(OrganizationalObjectType):
class WebhookType(OwnerMixin, CustomFieldsMixin, TagsMixin, ObjectType):
pass
@@ -231,5 +232,5 @@ class WebhookType(OrganizationalObjectType):
filters=EventRuleFilter,
pagination=True
)
class EventRuleType(OrganizationalObjectType):
class EventRuleType(OwnerMixin, CustomFieldsMixin, TagsMixin, ObjectType):
action_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None
+89
View File
@@ -0,0 +1,89 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extras', '0133_make_cf_minmax_decimal'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='configcontext',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='configcontextprofile',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='configtemplate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customfield',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customfieldchoiceset',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customlink',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='eventrule',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='exporttemplate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='savedfilter',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='tag',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='webhook',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]
+9 -2
View File
@@ -13,6 +13,7 @@ from extras.models.mixins import RenderTemplateMixin
from extras.querysets import ConfigContextQuerySet
from netbox.models import ChangeLoggedModel, PrimaryModel
from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
from netbox.models.mixins import OwnerMixin
from utilities.data import deepmerge
from utilities.jsonschema import validate_schema
@@ -68,7 +69,7 @@ class ConfigContextProfile(SyncedDataMixin, PrimaryModel):
sync_data.alters_data = True
class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, ChangeLoggedModel):
class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, OwnerMixin, ChangeLoggedModel):
"""
A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned
qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B
@@ -266,7 +267,13 @@ class ConfigContextModel(models.Model):
#
class ConfigTemplate(
RenderTemplateMixin, SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel
RenderTemplateMixin,
SyncedDataMixin,
CustomLinksMixin,
ExportTemplatesMixin,
OwnerMixin,
TagsMixin,
ChangeLoggedModel,
):
name = models.CharField(
verbose_name=_('name'),
+3 -2
View File
@@ -21,6 +21,7 @@ from extras.choices import *
from extras.data import CHOICE_SETS
from netbox.models import ChangeLoggedModel
from netbox.models.features import CloningMixin, ExportTemplatesMixin
from netbox.models.mixins import OwnerMixin
from netbox.search import FieldTypes
from utilities import filters
from utilities.datetime import datetime_from_timestamp
@@ -70,7 +71,7 @@ class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)):
}
class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
object_types = models.ManyToManyField(
to='contenttypes.ContentType',
related_name='custom_fields',
@@ -773,7 +774,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
raise ValidationError(_("Required field cannot be empty."))
class CustomFieldChoiceSet(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class CustomFieldChoiceSet(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
"""
Represents a set of choices available for choice and multi-choice custom fields.
"""
+13 -5
View File
@@ -25,6 +25,7 @@ from netbox.models import ChangeLoggedModel
from netbox.models.features import (
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, has_feature
)
from netbox.models.mixins import OwnerMixin
from utilities.html import clean_html
from utilities.jinja2 import render_jinja2
from utilities.querydict import dict_to_querydict
@@ -44,7 +45,7 @@ __all__ = (
)
class EventRule(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel):
class EventRule(CustomFieldsMixin, ExportTemplatesMixin, OwnerMixin, TagsMixin, ChangeLoggedModel):
"""
An EventRule defines an action to be taken automatically in response to a specific set of events, such as when a
specific type of object is created, modified, or deleted. The action to be taken might entail transmitting a
@@ -155,7 +156,7 @@ class EventRule(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLogged
return False
class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel):
class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, OwnerMixin, ChangeLoggedModel):
"""
A Webhook defines a request that will be sent to a remote application when an object is created, updated, and/or
delete in NetBox. The request will contain a representation of the object, which the remote application can act on.
@@ -294,7 +295,7 @@ class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedMo
return render_jinja2(self.payload_url, context)
class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class CustomLink(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
"""
A custom link to an external representation of a NetBox object. The link text and URL fields accept Jinja2 template
code to be rendered with an object as context.
@@ -394,7 +395,14 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
}
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderTemplateMixin):
class ExportTemplate(
SyncedDataMixin,
CloningMixin,
ExportTemplatesMixin,
OwnerMixin,
ChangeLoggedModel,
RenderTemplateMixin,
):
object_types = models.ManyToManyField(
to='contenttypes.ContentType',
related_name='export_templates',
@@ -456,7 +464,7 @@ class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, Change
return _context
class SavedFilter(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
class SavedFilter(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
"""
A set of predefined keyword parameters that can be reused to filter for specific objects.
"""
+2 -1
View File
@@ -8,6 +8,7 @@ from taggit.models import TagBase, GenericTaggedItemBase
from netbox.choices import ColorChoices
from netbox.models import ChangeLoggedModel
from netbox.models.features import CloningMixin, ExportTemplatesMixin
from netbox.models.mixins import OwnerMixin
from utilities.fields import ColorField
from utilities.querysets import RestrictedQuerySet
@@ -21,7 +22,7 @@ __all__ = (
# Tags
#
class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase):
class Tag(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel, TagBase):
id = models.BigAutoField(
primary_key=True
)
+43 -3
View File
@@ -10,7 +10,7 @@ from core.tables import JobTable
from core.models import Job
from netbox.constants import EMPTY_TABLE_TEXT
from netbox.events import get_event_text
from netbox.tables import BaseTable, NetBoxTable, columns
from netbox.tables import BaseTable, NetBoxTable, PrimaryModelTable, columns
from .columns import NotificationActionsColumn
__all__ = (
@@ -109,6 +109,10 @@ class CustomFieldTable(NetBoxTable):
validation_regex = tables.Column(
verbose_name=_('Validation Regex'),
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta):
model = CustomField
@@ -146,6 +150,10 @@ class CustomFieldChoiceSetTable(NetBoxTable):
verbose_name=_('Order Alphabetically'),
false_mark=None
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta):
model = CustomFieldChoiceSet
@@ -171,6 +179,10 @@ class CustomLinkTable(NetBoxTable):
verbose_name=_('New Window'),
false_mark=None
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta):
model = CustomLink
@@ -214,6 +226,10 @@ class ExportTemplateTable(NetBoxTable):
orderable=False,
verbose_name=_('Synced')
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta):
model = ExportTemplate
@@ -294,6 +310,10 @@ class SavedFilterTable(NetBoxTable):
verbose_name=_('Shared'),
false_mark=None
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
def value_parameters(self, value):
return json.dumps(value)
@@ -450,6 +470,10 @@ class WebhookTable(NetBoxTable):
ssl_validation = columns.BooleanColumn(
verbose_name=_('SSL Validation')
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn(
url_name='extras:webhook_list'
)
@@ -488,6 +512,10 @@ class EventRuleTable(NetBoxTable):
func=get_event_text,
orderable=False
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn(
url_name='extras:webhook_list'
)
@@ -514,6 +542,10 @@ class TagTable(NetBoxTable):
object_types = columns.ContentTypesColumn(
verbose_name=_('Object Types'),
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta):
model = Tag
@@ -547,7 +579,7 @@ class TaggedItemTable(NetBoxTable):
fields = ('id', 'content_type', 'content_object')
class ConfigContextProfileTable(NetBoxTable):
class ConfigContextProfileTable(PrimaryModelTable):
name = tables.Column(
verbose_name=_('Name'),
linkify=True
@@ -568,7 +600,7 @@ class ConfigContextProfileTable(NetBoxTable):
url_name='extras:configcontextprofile_list'
)
class Meta(NetBoxTable.Meta):
class Meta(PrimaryModelTable.Meta):
model = ConfigContextProfile
fields = (
'pk', 'id', 'name', 'description', 'comments', 'data_source', 'data_file', 'is_synced', 'tags', 'created',
@@ -601,6 +633,10 @@ class ConfigContextTable(NetBoxTable):
orderable=False,
verbose_name=_('Synced')
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn(
url_name='extras:configcontext_list'
)
@@ -645,6 +681,10 @@ class ConfigTemplateTable(NetBoxTable):
verbose_name=_('As Attachment'),
false_mark=None
)
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn(
url_name='extras:configtemplate_list'
)