dev: notification models and operations

This commit is contained in:
pablohashescobar 2023-06-22 18:38:51 +05:30
parent f80f98ddef
commit 0af49306a9
8 changed files with 126 additions and 18 deletions

View File

@ -75,4 +75,7 @@ from .estimate import (
) )
from .inbox import InboxSerializer, InboxIssueSerializer, IssueStateInboxSerializer from .inbox import InboxSerializer, InboxIssueSerializer, IssueStateInboxSerializer
from .analytic import AnalyticViewSerializer from .analytic import AnalyticViewSerializer
from .notification import NotificationSerializer

View File

@ -0,0 +1,10 @@
# Module imports
from .base import BaseSerializer
from plane.db.models import Notification
class NotificationSerializer(BaseSerializer):
class Meta:
model = Notification
fields = "__all__"

View File

@ -149,6 +149,9 @@ from plane.api.views import (
ExportAnalyticsEndpoint, ExportAnalyticsEndpoint,
DefaultAnalyticsEndpoint, DefaultAnalyticsEndpoint,
## End Analytics ## End Analytics
# Notification
NotificationViewSet,
## End Notification
) )
@ -803,11 +806,7 @@ urlpatterns = [
path( path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/subscribers/", "workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:issue_id>/subscribers/",
IssueSubscriberViewSet.as_view( IssueSubscriberViewSet.as_view(
{ {"get": "list", "post": "create", "delete": "destroy"}
"get": "list",
"post": "create",
"delete": "destroy"
}
), ),
name="project-issue-subscriber", name="project-issue-subscriber",
), ),
@ -1288,4 +1287,26 @@ urlpatterns = [
name="default-analytics", name="default-analytics",
), ),
## End Analytics ## End Analytics
# Notification
path(
"workspaces/<str:slug>/users/notifications/",
NotificationViewSet.as_view(
{
"get": "list",
}
),
name="notifications",
),
path(
"workspaces/<str:slug>/users/notifications/<uuid:pk>/",
NotificationViewSet.as_view(
{
"get": "retrieve",
"patch": "partial_update",
"delete": "destroy",
}
),
name="notifications",
),
## End Notification
] ]

View File

@ -134,6 +134,7 @@ from .estimate import (
from .release import ReleaseNotesEndpoint from .release import ReleaseNotesEndpoint
from .inbox import InboxViewSet, InboxIssueViewSet from .inbox import InboxViewSet, InboxIssueViewSet
from .analytic import ( from .analytic import (
AnalyticsEndpoint, AnalyticsEndpoint,
AnalyticViewViewset, AnalyticViewViewset,
@ -141,3 +142,5 @@ from .analytic import (
ExportAnalyticsEndpoint, ExportAnalyticsEndpoint,
DefaultAnalyticsEndpoint, DefaultAnalyticsEndpoint,
) )
from .notification import NotificationViewSet

View File

@ -0,0 +1,24 @@
# Third party imports
from rest_framework import status
from rest_framework.response import Response
# Module imports
from .base import BaseViewSet
from plane.db.models import Notification
from plane.api.serializers import NotificationSerializer
class NotificationViewSet(BaseViewSet):
model = Notification
serializer_class = NotificationSerializer
def get_queryset(self):
return (
super()
.get_queryset()
.filter(
workspace__slug=self.kwargs.get("slug"),
)
.select_related("workspace")
)

View File

@ -20,8 +20,10 @@ from plane.db.models import (
State, State,
Cycle, Cycle,
Module, Module,
IssueSubscriber,
Notification,
) )
from plane.api.serializers import IssueActivitySerializer from plane.api.serializers import IssueActivitySerializer, IssueFlatSerializer
# Track Chnages in name # Track Chnages in name
@ -992,18 +994,57 @@ def issue_activity(
# Post the updates to segway for integrations and webhooks # Post the updates to segway for integrations and webhooks
if len(issue_activities_created): if len(issue_activities_created):
# Don't send activities if the actor is a bot # Don't send activities if the actor is a bot
if settings.PROXY_BASE_URL: try:
for issue_activity in issue_activities_created: if settings.PROXY_BASE_URL:
headers = {"Content-Type": "application/json"} for issue_activity in issue_activities_created:
issue_activity_json = json.dumps( headers = {"Content-Type": "application/json"}
IssueActivitySerializer(issue_activity).data, issue_activity_json = json.dumps(
cls=DjangoJSONEncoder, IssueActivitySerializer(issue_activity).data,
) cls=DjangoJSONEncoder,
_ = requests.post( )
f"{settings.PROXY_BASE_URL}/hooks/workspaces/{str(issue_activity.workspace_id)}/projects/{str(issue_activity.project_id)}/issues/{str(issue_activity.issue_id)}/issue-activity-hooks/", _ = requests.post(
json=issue_activity_json, f"{settings.PROXY_BASE_URL}/hooks/workspaces/{str(issue_activity.workspace_id)}/projects/{str(issue_activity.project_id)}/issues/{str(issue_activity.issue_id)}/issue-activity-hooks/",
headers=headers, json=issue_activity_json,
headers=headers,
)
except Exception as e:
capture_exception(e)
# Create Notifications
bulk_notifications = []
issue_subscribers = (
IssueSubscriber.objects.filter(project=project)
.exclude(subscriber_id=actor_id)
.values_list("subscriber")
)
issue = Issue.objects.get(project=project, pk=issue_id)
for subscriber in issue_subscribers:
for issue_activity in issue_activities_created:
bulk_notifications.append(
Notification(
workspace=project.workspace,
sender="in_app:issue_activities",
triggered_by=actor,
receiver_id=subscriber,
entity_identifier=issue_id,
entity_name="issue",
project=project,
title=issue_activity.comment,
data={
"issue": {
"id": str(issue_id),
"identifier": str(project.identifier),
"sequence_id": issue.sequence_id,
"state_name": issue.state.name,
"state_group": issue.state.group,
},
"issue_activity": str(issue_activity.id),
},
) )
)
return return
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)

View File

@ -67,4 +67,7 @@ from .page import Page, PageBlock, PageFavorite, PageLabel
from .estimate import Estimate, EstimatePoint from .estimate import Estimate, EstimatePoint
from .inbox import Inbox, InboxIssue from .inbox import Inbox, InboxIssue
from .analytic import AnalyticView from .analytic import AnalyticView
from .notification import Notification

View File

@ -12,12 +12,15 @@ class Notification(BaseModel):
project = models.ForeignKey( project = models.ForeignKey(
"db.Project", related_name="notifications", on_delete=models.CASCADE, null=True "db.Project", related_name="notifications", on_delete=models.CASCADE, null=True
) )
data = models.JSONField(null=True)
entity_identifier = models.UUIDField(null=True) entity_identifier = models.UUIDField(null=True)
entity_name = models.CharField(max_length=255)
title = models.TextField() title = models.TextField()
message = models.JSONField(null=True) message = models.JSONField(null=True)
message_html = models.TextField(blank=True, default="<p></p>") message_html = models.TextField(blank=True, default="<p></p>")
message_stripped = models.TextField(blank=True, null=True) message_stripped = models.TextField(blank=True, null=True)
sender = models.ForeignKey("db.User", related_name="sent_notifications", on_delete=models.SET_NULL, null=True) sender = models.CharField(max_length=255)
triggered_by = models.ForeignKey("db.User", related_name="triggered_notifications", on_delete=models.SET_NULL, null=True)
receiver = models.ForeignKey("db.User", related_name="received_notifications", on_delete=models.CASCADE) receiver = models.ForeignKey("db.User", related_name="received_notifications", on_delete=models.CASCADE)
read_at = models.DateTimeField(null=True) read_at = models.DateTimeField(null=True)
snoozed_till = models.DateTimeField(null=True) snoozed_till = models.DateTimeField(null=True)