[MOBIL-1023]: chore: Add new fields to Inbox (Notification) query (#3539)

* dev: updated inbox query

* dev: handled the notification

* dev: handled the epic notifications

* chore: removed is_inbpx_issue field
This commit is contained in:
guru_sainath
2025-06-30 17:56:22 +05:30
committed by GitHub
parent b9649078b2
commit e77a0487e7
4 changed files with 94 additions and 32 deletions

View File

@@ -37,7 +37,7 @@ class NotificationViewSet(BaseViewSet, BasePaginator):
workspace__slug=self.kwargs.get("slug"),
receiver_id=self.request.user.id,
)
.select_related("workspace", "project," "triggered_by", "receiver")
.select_related("workspace", "project", "triggered_by", "receiver")
)
@allow_permission(

View File

@@ -27,7 +27,7 @@ class InboxViewSet(BaseViewSet, BasePaginator):
workspace__slug=self.kwargs.get("slug"),
receiver_id=self.request.user.id,
)
.select_related("workspace", "project," "triggered_by", "receiver")
.select_related("workspace", "project", "triggered_by", "receiver")
)
@check_feature_flag(FeatureFlag.INBOX_STACKING)

View File

@@ -41,24 +41,23 @@ class NotificationQuery:
type: Optional[JSON] = "all",
snoozed: Optional[bool] = None,
archived: Optional[bool] = None,
read: Optional[str] = None,
mentioned: Optional[bool] = False,
read: Optional[str] = None,
cursor: Optional[str] = None,
) -> PaginatorResponse[NotificationType]:
user = info.context.user
user_id = str(user.id)
type_list = type.split(",")
q_filters = Q()
filters = Q(workspace__slug=slug, receiver_id=user_id)
# Base QuerySet
# Teamspace Filter
project_teamspace_filter = await project_member_filter_via_teamspaces_async(
user_id=user_id, workspace_slug=slug
)
queryset = (
Notification.objects.filter(filters)
# Inbox Filters
notification_queryset = (
Notification.objects.filter(workspace__slug=slug)
.filter(receiver_id=user_id)
.filter(entity_name__in=["issue", "epic"])
.filter(project_teamspace_filter.query)
.distinct()
.select_related("workspace", "project", "triggered_by", "receiver")
@@ -66,38 +65,53 @@ class NotificationQuery:
)
now = timezone.now()
q_filters = Q()
# Apply snoozed filter
if snoozed is not None:
if snoozed:
queryset = queryset.filter(
notification_queryset = notification_queryset.filter(
Q(snoozed_till__lt=now) | Q(snoozed_till__isnull=False)
)
else:
queryset = queryset.filter(
notification_queryset = notification_queryset.filter(
Q(snoozed_till__gte=now) | Q(snoozed_till__isnull=True)
)
# Apply archived filter
if archived is not None:
if archived:
queryset = queryset.filter(archived_at__isnull=False)
notification_queryset = notification_queryset.filter(
archived_at__isnull=False
)
else:
queryset = queryset.filter(archived_at__isnull=True)
notification_queryset = notification_queryset.filter(
archived_at__isnull=True
)
# Apply read filter
if read is not None:
if read == "true":
queryset = queryset.filter(read_at__isnull=False)
notification_queryset = notification_queryset.filter(
read_at__isnull=False
)
elif read == "false":
queryset = queryset.filter(read_at__isnull=True)
notification_queryset = notification_queryset.filter(
read_at__isnull=True
)
# Apply mentioned filter
if mentioned:
queryset = queryset.filter(sender__icontains="mentioned")
notification_queryset = notification_queryset.filter(
sender__icontains="mentioned"
)
else:
queryset = queryset.exclude(sender__icontains="mentioned")
notification_queryset = notification_queryset.exclude(
sender__icontains="mentioned"
)
# Subscribed issues
type_list = type.split(",")
if "subscribed" in type_list:
issue_ids = await sync_to_async(list)(
IssueSubscriber.objects.filter(
@@ -105,7 +119,9 @@ class NotificationQuery:
)
.annotate(
created=Exists(
Issue.objects.filter(created_by=user, pk=OuterRef("issue_id"))
Issue.objects.filter(
created_by=user, pk=OuterRef("issue_id")
).filter(Q(type__isnull=True) | Q(type__is_epic=False))
)
)
.annotate(
@@ -141,16 +157,16 @@ class NotificationQuery:
)()
if has_permission:
queryset = queryset.none()
notification_queryset = notification_queryset.none()
else:
issue_ids = await sync_to_async(list)(
Issue.objects.filter(
workspace__slug=slug, created_by=user
).values_list("pk", flat=True)
Issue.objects.filter(workspace__slug=slug, created_by=user)
.filter(Q(type__isnull=True) | Q(type__is_epic=False))
.values_list("pk", flat=True)
)
q_filters = Q(entity_identifier__in=issue_ids)
queryset = queryset.filter(q_filters)
notifications = await sync_to_async(list)(queryset)
notification_queryset = notification_queryset.filter(q_filters)
notifications = await sync_to_async(list)(notification_queryset)
return paginate(results_object=notifications, cursor=cursor)

View File

@@ -1,19 +1,23 @@
# Python imports
from typing import Optional
from datetime import datetime
from asgiref.sync import sync_to_async
from typing import Optional
# Strawberry imports
import strawberry
import strawberry_django
from asgiref.sync import sync_to_async
# Django imports
from django.db.models import Q
from strawberry.scalars import JSON
from plane.db.models import Issue, Notification
from plane.graphql.types.project import ProjectType
from plane.graphql.types.users import UserType
from plane.graphql.utils.issue_activity import issue_activity_comment_string
# Module imports
from plane.graphql.utils.timezone import user_timezone_converter
from plane.db.models import Notification
from plane.graphql.types.users import UserType
from plane.graphql.types.project import ProjectType
from plane.graphql.utils.issue_activity import issue_activity_comment_string
@strawberry_django.type(Notification)
@@ -97,3 +101,45 @@ class NotificationType:
return self.data
return await process_data()
@strawberry.field
async def is_intake_issue(self) -> bool:
workspace_slug = await sync_to_async(lambda: self.workspace.slug)()
work_item_id = self.entity_identifier
if not workspace_slug or not work_item_id:
return False
is_intake_issue = await sync_to_async(list)(
Issue.objects.filter(
workspace__slug=workspace_slug,
pk=work_item_id,
issue_intake__status__in=[0, 2, -2],
)
)
return bool(is_intake_issue)
@strawberry.field
async def is_mentioned_notification(self) -> bool:
is_mentioned_notification = (
True if "mentioned" in self.sender.lower() else False
)
return is_mentioned_notification
@strawberry.field
async def is_epic(self) -> bool:
workspace_slug = await sync_to_async(lambda: self.workspace.slug)()
work_item_id = self.entity_identifier
if not work_item_id or not workspace_slug:
return False
is_epic_work_item = await sync_to_async(list)(
Issue.objects.filter(
pk=work_item_id, workspace__slug=workspace_slug
).filter(Q(type__isnull=False) & Q(type__is_epic=True))
)
return bool(is_epic_work_item)