Closes #15621: User notifications (#16800)

* Initial work on #15621

* Signal receiver should ignore models which don't support notifications

* Flesh out NotificationGroup functionality

* Add NotificationGroup filters for users & groups

* Separate read & dimiss actions

* Enable one-click dismissals from notifications list

* Include total notification count in dropdown

* Drop 'kind' field from Notification model

* Register event types in the registry; add colors & icons

* Enable event rules to target notification groups

* Define dynamic choices for Notification.event_name

* Move event registration to core

* Add more job events

* Misc cleanup

* Misc cleanup

* Correct absolute URLs for notifications & subscriptions

* Optimize subscriber notifications

* Use core event types when queuing events

* Standardize queued event attribute to event_type; change content_type to object_type

* Rename Notification.event_name to event_type

* Restore NotificationGroupBulkEditView

* Add API tests

* Add view & filterset tests

* Add model documentation

* Fix tests

* Update notification bell when notifications have been cleared

* Ensure subscribe button appears only on relevant models

* Notifications/subscriptions cannot be ordered by object

* Misc cleanup

* Add event icon & type to notifications table

* Adjust icon sizing

* Mute color of read notifications

* Misc cleanup
This commit is contained in:
Jeremy Stretch
2024-07-15 14:24:11 -04:00
committed by GitHub
parent 1c2336be60
commit b0e7294bc1
59 changed files with 1913 additions and 90 deletions

View File

@@ -8,6 +8,7 @@ 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 tenancy.models import Tenant, TenantGroup
from users.models import Group, User
from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
from virtualization.models import Cluster, ClusterGroup, ClusterType
from .choices import *
@@ -26,6 +27,7 @@ __all__ = (
'ImageAttachmentFilterSet',
'JournalEntryFilterSet',
'LocalConfigContextFilterSet',
'NotificationGroupFilterSet',
'ObjectTypeFilterSet',
'SavedFilterFilterSet',
'ScriptFilterSet',
@@ -336,6 +338,49 @@ class BookmarkFilterSet(BaseFilterSet):
fields = ('id', 'object_id')
class NotificationGroupFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
)
user_id = django_filters.ModelMultipleChoiceFilter(
field_name='users',
queryset=User.objects.all(),
label=_('User (ID)'),
)
user = django_filters.ModelMultipleChoiceFilter(
field_name='users__username',
queryset=User.objects.all(),
to_field_name='username',
label=_('User (name)'),
)
group_id = django_filters.ModelMultipleChoiceFilter(
field_name='groups',
queryset=Group.objects.all(),
label=_('Group (ID)'),
)
group = django_filters.ModelMultipleChoiceFilter(
field_name='groups__name',
queryset=Group.objects.all(),
to_field_name='name',
label=_('Group (name)'),
)
class Meta:
model = NotificationGroup
fields = (
'id', 'name', 'description',
)
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(description__icontains=value)
)
class ImageAttachmentFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',