Arthur 2 лет назад
Родитель
Сommit
46b0df43f9

+ 149 - 0
netbox/extras/graphql/filters.py

@@ -0,0 +1,149 @@
+import strawberry
+from strawberry import auto
+from extras import models, filtersets
+
+__all__ = (
+    'ConfigContextFilter',
+    'ConfigTemplateFilter',
+    'CustomFieldFilter',
+    'CustomFieldChoiceSetFilter',
+    'CustomLinkFilter',
+    'ExportTemplateFilter',
+    'ImageAttachmentFilter',
+    'JournalEntryFilter',
+    'ObjectChangeFilter',
+    'SavedFilterFilter',
+    'TagFilter',
+    'WebhookFilter',
+)
+
+
+@strawberry.django.filter(models.ConfigContext, lookups=True)
+class ConfigContextFilter(filtersets.ConfigContextFilterSet):
+    id: auto
+    name: auto
+    is_active: auto
+    data_synced: auto
+
+
+@strawberry.django.filter(models.ConfigTemplate, lookups=True)
+class ConfigTemplateFilter(filtersets.ConfigTemplateFilterSet):
+    id: auto
+    name: auto
+    description: auto
+    data_synced: auto
+
+
+@strawberry.django.filter(models.CustomField, lookups=True)
+class CustomFieldFilter(filtersets.CustomFieldFilterSet):
+    id: auto
+    content_types: auto
+    name: auto
+    group_name: auto
+    required: auto
+    search_weight: auto
+    filter_logic: auto
+    ui_visibility: auto
+    weight: auto
+    is_cloneable: auto
+    description: auto
+
+
+@strawberry.django.filter(models.CustomFieldChoiceSet, lookups=True)
+class CustomFieldChoiceSetFilter(filtersets.CustomFieldChoiceSetFilterSet):
+    id: auto
+    name: auto
+    description: auto
+    base_choices: auto
+    order_alphabetically: auto
+
+
+@strawberry.django.filter(models.CustomLink, lookups=True)
+class CustomLinkFilter(filtersets.CustomLinkFilterSet):
+    id: auto
+    content_types: auto
+    name: auto
+    enabled: auto
+    link_text: auto
+    link_url: auto
+    weight: auto
+    group_name: auto
+    new_window: auto
+
+
+@strawberry.django.filter(models.ExportTemplate, lookups=True)
+class ExportTemplateFilter(filtersets.ExportTemplateFilterSet):
+    id: auto
+    content_types: auto
+    name: auto
+    description: auto
+    data_synced: auto
+
+
+@strawberry.django.filter(models.ImageAttachment, lookups=True)
+class ImageAttachmentFilter(filtersets.ImageAttachmentFilterSet):
+    id: auto
+    content_type_id: auto
+    object_id: auto
+    name: auto
+
+
+@strawberry.django.filter(models.JournalEntry, lookups=True)
+class JournalEntryFilter(filtersets.JournalEntryFilterSet):
+    id: auto
+    assigned_object_type_id: auto
+    assigned_object_id: auto
+    created: auto
+    kind: auto
+
+
+@strawberry.django.filter(models.ObjectChange, lookups=True)
+class ObjectChangeFilter(filtersets.ObjectChangeFilterSet):
+    id: auto
+    user: auto
+    user_name: auto
+    request_id: auto
+    action: auto
+    changed_object_type_id: auto
+    changed_object_id: auto
+    object_repr: auto
+
+
+@strawberry.django.filter(models.SavedFilter, lookups=True)
+class SavedFilterFilter(filtersets.SavedFilterFilterSet):
+    id: auto
+    content_types: auto
+    name: auto
+    slug: auto
+    description: auto
+    enabled: auto
+    shared: auto
+    weight: auto
+
+
+@strawberry.django.filter(models.Tag, lookups=True)
+class TagFilter(filtersets.TagFilterSet):
+    id: auto
+    name: auto
+    slug: auto
+    # color: auto
+    description: auto
+    object_types: auto
+
+
+@strawberry.django.filter(models.Webhook, lookups=True)
+class WebhookFilter(filtersets.WebhookFilterSet):
+    id: auto
+    name: auto
+    type_create: auto
+    type_update: auto
+    type_delete: auto
+    type_job_start: auto
+    type_job_end: auto
+    payload_url: auto
+    enabled: auto
+    http_method: auto
+    http_content_type: auto
+    secret: auto
+    ssl_verification: auto
+    ca_file_path: auto

+ 27 - 16
netbox/extras/graphql/mixins.py

@@ -1,7 +1,7 @@
 import strawberry
-import graphene
+from typing import TYPE_CHECKING, Annotated, List
+
 from django.contrib.contenttypes.models import ContentType
-from graphene.types.generic import GenericScalar
 
 from extras.models import ObjectChange
 
@@ -14,11 +14,16 @@ __all__ = (
     'TagsMixin',
 )
 
+if TYPE_CHECKING:
+    from .types import ImageAttachmentType, JournalEntryType, ObjectChangeType, TagType
+    from tenancy.graphql.types import ContactAssignmentType
+
 
+@strawberry.type
 class ChangelogMixin:
-    changelog = graphene.List('extras.graphql.types.ObjectChangeType')
 
-    def resolve_changelog(self, info):
+    @strawberry.django.field
+    def changelog(self) -> List[Annotated["ObjectChangeType", strawberry.lazy('.types')]]:
         content_type = ContentType.objects.get_for_model(self)
         object_changes = ObjectChange.objects.filter(
             changed_object_type=content_type,
@@ -27,43 +32,49 @@ class ChangelogMixin:
         return object_changes.restrict(info.context.user, 'view')
 
 
+@strawberry.type
 class ConfigContextMixin:
-    config_context = GenericScalar()
 
-    def resolve_config_context(self, info):
+    @strawberry.django.field
+    def config_context(self) -> strawberry.scalars.JSON:
         return self.get_config_context()
 
 
+@strawberry.type
 class CustomFieldsMixin:
-    custom_fields = GenericScalar()
 
-    def resolve_custom_fields(self, info):
+    @strawberry.django.field
+    def custom_fields(self) -> strawberry.scalars.JSON:
         return self.custom_field_data
 
 
+@strawberry.type
 class ImageAttachmentsMixin:
-    image_attachments = graphene.List('extras.graphql.types.ImageAttachmentType')
 
-    def resolve_image_attachments(self, info):
+    @strawberry.django.field
+    def image_attachments(self) -> List[Annotated["ImageAttachmentType", strawberry.lazy('.types')]]:
         return self.images.restrict(info.context.user, 'view')
 
 
+@strawberry.type
 class JournalEntriesMixin:
-    journal_entries = graphene.List('extras.graphql.types.JournalEntryType')
 
-    def resolve_journal_entries(self, info):
+    @strawberry.django.field
+    def journal_entries(self) -> List[Annotated["JournalEntryType", strawberry.lazy('.types')]]:
         return self.journal_entries.restrict(info.context.user, 'view')
 
 
+@strawberry.type
 class TagsMixin:
-    tags = graphene.List('extras.graphql.types.TagType')
 
-    def resolve_tags(self, info):
+    @strawberry.django.field
+    def tags(self) -> List[Annotated["TagType", strawberry.lazy('.types')]]:
         return self.tags.all()
 
 
+@strawberry.type
 class ContactsMixin:
-    contacts = graphene.List('tenancy.graphql.types.ContactAssignmentType')
 
-    def resolve_contacts(self, info):
+    @strawberry.django.field
+    def contacts(self) -> List[Annotated["ContactAssignmentType", strawberry.lazy('tenancy.graphql.types')]]:
         return list(self.contacts.all())

+ 76 - 60
netbox/extras/graphql/types.py

@@ -1,6 +1,10 @@
+import strawberry
+from strawberry import auto
+
 from extras import filtersets, models
 from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
 from netbox.graphql.types import BaseObjectType, ObjectType, OrganizationalObjectType
+from .filters import *
 
 __all__ = (
     'ConfigContextType',
@@ -18,97 +22,109 @@ __all__ = (
 )
 
 
+@strawberry.django.type(
+    models.ConfigContext,
+    fields='__all__',
+    filters=ConfigContextFilter
+)
 class ConfigContextType(ObjectType):
-
-    class Meta:
-        model = models.ConfigContext
-        fields = '__all__'
-        filterset_class = filtersets.ConfigContextFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.ConfigTemplate,
+    fields='__all__',
+    filters=ConfigTemplateFilter
+)
 class ConfigTemplateType(TagsMixin, ObjectType):
-
-    class Meta:
-        model = models.ConfigTemplate
-        fields = '__all__'
-        filterset_class = filtersets.ConfigTemplateFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.CustomField,
+    fields='__all__',
+    filters=CustomFieldFilter
+)
 class CustomFieldType(ObjectType):
-
-    class Meta:
-        model = models.CustomField
-        exclude = ('content_types', )
-        filterset_class = filtersets.CustomFieldFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.CustomFieldChoiceSet,
+    fields='__all__',
+    filters=CustomFieldChoiceSetFilter
+)
 class CustomFieldChoiceSetType(ObjectType):
-
-    class Meta:
-        model = models.CustomFieldChoiceSet
-        fields = '__all__'
-        filterset_class = filtersets.CustomFieldChoiceSetFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.CustomLink,
+    fields='__all__',
+    filters=CustomLinkFilter
+)
 class CustomLinkType(ObjectType):
-
-    class Meta:
-        model = models.CustomLink
-        exclude = ('content_types', )
-        filterset_class = filtersets.CustomLinkFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.ExportTemplate,
+    fields='__all__',
+    filters=ExportTemplateFilter
+)
 class ExportTemplateType(ObjectType):
-
-    class Meta:
-        model = models.ExportTemplate
-        exclude = ('content_types', )
-        filterset_class = filtersets.ExportTemplateFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.ImageAttachment,
+    fields='__all__',
+    filters=ImageAttachmentFilter
+)
 class ImageAttachmentType(BaseObjectType):
-
-    class Meta:
-        model = models.ImageAttachment
-        fields = '__all__'
-        filterset_class = filtersets.ImageAttachmentFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.JournalEntry,
+    fields='__all__',
+    filters=JournalEntryFilter
+)
 class JournalEntryType(CustomFieldsMixin, TagsMixin, ObjectType):
-
-    class Meta:
-        model = models.JournalEntry
-        fields = '__all__'
-        filterset_class = filtersets.JournalEntryFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.ObjectChange,
+    fields='__all__',
+    filters=ObjectChangeFilter
+)
 class ObjectChangeType(BaseObjectType):
-
-    class Meta:
-        model = models.ObjectChange
-        fields = '__all__'
-        filterset_class = filtersets.ObjectChangeFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.SavedFilter,
+    exclude=['content_types',],
+    filters=SavedFilterFilter
+)
 class SavedFilterType(ObjectType):
-
-    class Meta:
-        model = models.SavedFilter
-        exclude = ('content_types', )
-        filterset_class = filtersets.SavedFilterFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.Tag,
+    exclude=['extras_taggeditem_items', 'color'],  # bug - remove color from exclude
+    filters=TagFilter
+)
 class TagType(ObjectType):
-
-    class Meta:
-        model = models.Tag
-        exclude = ('extras_taggeditem_items',)
-        filterset_class = filtersets.TagFilterSet
+    pass
 
 
+@strawberry.django.type(
+    models.Webhook,
+    exclude=['content_types',],
+    filters=WebhookFilter
+)
 class WebhookType(OrganizationalObjectType):
-
-    class Meta:
-        model = models.Webhook
-        exclude = ('content_types', )
-        filterset_class = filtersets.WebhookFilterSet
+    pass

+ 12 - 10
netbox/netbox/graphql/types.py

@@ -21,23 +21,24 @@ __all__ = (
 # Base types
 #
 
+@strawberry.type
 class BaseObjectType:
     """
     Base GraphQL object type for all NetBox objects. Restricts the model queryset to enforce object permissions.
     """
-    display: auto
-    class_type: auto
 
     @classmethod
     def get_queryset(cls, queryset, info):
         # Enforce object permissions on the queryset
         return queryset.restrict(info.context.request.user, 'view')
 
-    def resolve_display(parent, info, **kwargs):
-        return str(parent)
+    @strawberry.django.field
+    def display(self) -> str:
+        return str(self)
 
-    def resolve_class_type(parent, info, **kwargs):
-        return parent.__class__.__name__
+    @strawberry.django.field
+    def class_type(self) -> str:
+        return self.__class__.__name__
 
 
 class ObjectType(
@@ -79,8 +80,9 @@ class NetBoxObjectType(
 # Miscellaneous types
 #
 
+@strawberry.django.type(
+    ContentType,
+    fields=['id', 'app_label', 'model'],
+)
 class ContentTypeType:
-
-    class Meta:
-        model = ContentType
-        fields = ('id', 'app_label', 'model')
+    pass