chore: notifications (#1515)

* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: triggered_by details

* dev: add bot filtering

* dev: unread notification count endpoint

* dev: update endpoint to send count for all notification types
This commit is contained in:
Nikhil 2023-07-17 13:17:48 +05:30 committed by GitHub
parent e0181342c0
commit b69c4b6b30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 7 deletions

View File

@ -1,9 +1,12 @@
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer
from plane.db.models import Notification from plane.db.models import Notification
class NotificationSerializer(BaseSerializer): class NotificationSerializer(BaseSerializer):
triggered_by_details = UserLiteSerializer(read_only=True, source="triggered_by")
class Meta: class Meta:
model = Notification model = Notification
fields = "__all__" fields = "__all__"

View File

@ -153,6 +153,7 @@ from plane.api.views import (
## End Analytics ## End Analytics
# Notification # Notification
NotificationViewSet, NotificationViewSet,
UnreadNotificationEndpoint,
## End Notification ## End Notification
) )
@ -1382,5 +1383,10 @@ urlpatterns = [
), ),
name="notifications", name="notifications",
), ),
path(
"workspaces/<str:slug>/users/notifications/unread/",
UnreadNotificationEndpoint.as_view(),
name="unread-notifications",
),
## End Notification ## End Notification
] ]

View File

@ -145,4 +145,4 @@ from .analytic import (
DefaultAnalyticsEndpoint, DefaultAnalyticsEndpoint,
) )
from .notification import NotificationViewSet from .notification import NotificationViewSet, UnreadNotificationEndpoint

View File

@ -8,7 +8,7 @@ from rest_framework.response import Response
from sentry_sdk import capture_exception from sentry_sdk import capture_exception
# Module imports # Module imports
from .base import BaseViewSet from .base import BaseViewSet, BaseAPIView
from plane.db.models import Notification, IssueAssignee, IssueSubscriber, Issue from plane.db.models import Notification, IssueAssignee, IssueSubscriber, Issue
from plane.api.serializers import NotificationSerializer from plane.api.serializers import NotificationSerializer
@ -25,7 +25,7 @@ class NotificationViewSet(BaseViewSet):
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
receiver_id=self.request.user.id, receiver_id=self.request.user.id,
) )
.select_related("workspace") .select_related("workspace", "project," "triggered_by", "receiver")
) )
def list(self, request, slug): def list(self, request, slug):
@ -123,7 +123,7 @@ class NotificationViewSet(BaseViewSet):
{"error": "Something went wrong please try again later"}, {"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
def mark_read(self, request, slug, pk): def mark_read(self, request, slug, pk):
try: try:
notification = Notification.objects.get( notification = Notification.objects.get(
@ -166,7 +166,6 @@ class NotificationViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
def archive(self, request, slug, pk): def archive(self, request, slug, pk):
try: try:
notification = Notification.objects.get( notification = Notification.objects.get(
@ -209,3 +208,48 @@ class NotificationViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
class UnreadNotificationEndpoint(BaseAPIView):
def get(self, request, slug):
try:
# Watching Issues Count
watching_notification_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
entity_identifier__in=IssueSubscriber.objects.filter(
workspace__slug=slug, subscriber_id=request.user.id
).values_list("issue_id", flat=True),
).count()
# My Issues Count
my_issues_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
entity_identifier__in=IssueAssignee.objects.filter(
workspace__slug=slug, assignee_id=request.user.id
).values_list("issue_id", flat=True),
).count()
# Created Issues Count
created_issues_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
entity_identifier__in=Issue.objects.filter(
workspace__slug=slug, created_by=request.user
).values_list("pk", flat=True),
).count()
return Response(
{
"watching_notifications": watching_notification_count,
"my_issues": my_issues_count,
"created_issues": created_issues_count,
},
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@ -1109,7 +1109,8 @@ def issue_activity(
issue_subscribers = issue_subscribers + issue_assignees issue_subscribers = issue_subscribers + issue_assignees
if issue.created_by_id: # Add bot filtering
if issue.created_by_id is not None and not issue.created_by.is_bot:
issue_subscribers = issue_subscribers + [issue.created_by_id] issue_subscribers = issue_subscribers + [issue.created_by_id]
issue = Issue.objects.get(project=project, pk=issue_id) issue = Issue.objects.get(project=project, pk=issue_id)
@ -1134,7 +1135,17 @@ def issue_activity(
"state_name": issue.state.name, "state_name": issue.state.name,
"state_group": issue.state.group, "state_group": issue.state.group,
}, },
"issue_activity": str(issue_activity.id), "issue_activity": {
"id": str(issue_activity.id),
"verb": str(issue_activity.verb),
"field": str(issue_activity.field),
"actor": str(issue_activity.actor_id),
"new_value": str(issue_activity.new_value),
"old_value": str(issue_activity.old_value),
"issue_comment": str(
issue_activity.issue_comment.comment_stripped if issue_activity.issue_comment is not None else ""
),
},
}, },
) )
) )