From eeca184cb882d978ddd3f2c68fe9540124b4736a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 May 2026 11:45:59 -0400 Subject: [PATCH] Closes #22057: Add GraphQL filters for notifications and subscriptions (#22175) --- netbox/extras/graphql/filters.py | 34 ++++++++++++++++++++++++++++++-- netbox/extras/graphql/types.py | 4 ++-- netbox/extras/tests/test_api.py | 6 ++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/netbox/extras/graphql/filters.py b/netbox/extras/graphql/filters.py index 30de07f05..2f5ea4dee 100644 --- a/netbox/extras/graphql/filters.py +++ b/netbox/extras/graphql/filters.py @@ -1,15 +1,16 @@ +from datetime import datetime from typing import TYPE_CHECKING, Annotated import strawberry import strawberry_django from django.db.models import Q, QuerySet from strawberry.scalars import ID -from strawberry_django import BaseFilterLookup, FilterLookup, StrFilterLookup +from strawberry_django import BaseFilterLookup, DatetimeFilterLookup, FilterLookup, StrFilterLookup from extras import models from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin from netbox.graphql.filter_mixins import SyncedDataFilterMixin -from netbox.graphql.filters import ChangeLoggedModelFilter, PrimaryModelFilter +from netbox.graphql.filters import BaseModelFilter, ChangeLoggedModelFilter, PrimaryModelFilter if TYPE_CHECKING: from core.graphql.filters import ContentTypeFilter @@ -41,8 +42,10 @@ __all__ = ( 'ExportTemplateFilter', 'ImageAttachmentFilter', 'JournalEntryFilter', + 'NotificationFilter', 'NotificationGroupFilter', 'SavedFilterFilter', + 'SubscriptionFilter', 'TableConfigFilter', 'TagFilter', 'WebhookFilter', @@ -291,6 +294,21 @@ class JournalEntryFilter(CustomFieldsFilterMixin, TagsFilterMixin, ChangeLoggedM comments: StrFilterLookup[str] | None = strawberry_django.filter_field() +@strawberry_django.filter_type(models.Notification, lookups=True) +class NotificationFilter(BaseModelFilter): + created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + read: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + user_id: ID | None = strawberry_django.filter_field() + object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + object_type_id: ID | None = strawberry_django.filter_field() + object_id: ID | None = strawberry_django.filter_field() + object_repr: StrFilterLookup[str] | None = strawberry_django.filter_field() + event_type: StrFilterLookup[str] | None = strawberry_django.filter_field() + + @strawberry_django.filter_type(models.NotificationGroup, lookups=True) class NotificationGroupFilter(ChangeLoggedModelFilter): name: StrFilterLookup[str] | None = strawberry_django.filter_field() @@ -316,6 +334,18 @@ class SavedFilterFilter(ChangeLoggedModelFilter): ) +@strawberry_django.filter_type(models.Subscription, lookups=True) +class SubscriptionFilter(BaseModelFilter): + created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field() + user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field() + user_id: ID | None = strawberry_django.filter_field() + object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = ( + strawberry_django.filter_field() + ) + object_type_id: ID | None = strawberry_django.filter_field() + object_id: ID | None = strawberry_django.filter_field() + + @strawberry_django.filter_type(models.TableConfig, lookups=True) class TableConfigFilter(ChangeLoggedModelFilter): name: StrFilterLookup[str] | None = strawberry_django.filter_field() diff --git a/netbox/extras/graphql/types.py b/netbox/extras/graphql/types.py index bed77aad0..42241543c 100644 --- a/netbox/extras/graphql/types.py +++ b/netbox/extras/graphql/types.py @@ -161,7 +161,7 @@ class JournalEntryType(CustomFieldsMixin, TagsMixin, ObjectType): @strawberry_django.type( models.Notification, - # filters=NotificationFilter + filters=NotificationFilter, pagination=True ) class NotificationType(ObjectType): @@ -190,7 +190,7 @@ class SavedFilterType(OwnerMixin, ObjectType): @strawberry_django.type( models.Subscription, - # filters=NotificationFilter + filters=SubscriptionFilter, pagination=True ) class SubscriptionType(ObjectType): diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index d9456c128..17d80f08f 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -1239,6 +1239,9 @@ class CreatedUpdatedFilterTestCase(APITestCase): class SubscriptionTestCase(APIViewTestCases.APIViewTestCase): model = Subscription brief_fields = ['display', 'id', 'object_id', 'object_type', 'url', 'user'] + graphql_filter = { + 'id': {'lookup': 'gt', 'value': '0'}, + } @classmethod def setUpTestData(cls): @@ -1378,6 +1381,9 @@ class NotificationTestCase(APIViewTestCases.APIViewTestCase): bulk_update_data = { 'read': now(), } + graphql_filter = { + 'event_type': {'lookup': 'exact', 'value': OBJECT_CREATED}, + } @classmethod def setUpTestData(cls):