124 lines
4.7 KiB
Python
124 lines
4.7 KiB
Python
# Copyright (c) 2023-present Plane Software, Inc. and contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# See the LICENSE file for details.
|
|
|
|
import json
|
|
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
from django.utils import timezone
|
|
from django.utils.html import escape
|
|
|
|
from plane.app.serializers import IssueCommentSerializer
|
|
from plane.db.models import IssueComment, Notification, Project
|
|
|
|
|
|
EXTERNAL_CONTOUR_NOTIFICATION_FIELDS = {"state", "comment", "attachment", "description"}
|
|
|
|
|
|
def build_external_contour_comment_html(comment: str) -> str:
|
|
escaped_comment = escape((comment or "").strip())
|
|
escaped_comment = escaped_comment.replace("\n", "<br />")
|
|
return f"<p>{escaped_comment}</p>"
|
|
|
|
|
|
def create_external_contour_issue_comment(*, issue, actor, comment: str, origin: str):
|
|
from plane.bgtasks.issue_activities_task import issue_activity
|
|
|
|
comment_html = build_external_contour_comment_html(comment)
|
|
serializer = IssueCommentSerializer(data={"comment_html": comment_html})
|
|
serializer.is_valid(raise_exception=True)
|
|
serializer.save(project_id=issue.project_id, issue_id=issue.id, actor=actor)
|
|
issue_activity.delay(
|
|
type="comment.activity.created",
|
|
requested_data=json.dumps(serializer.data, cls=DjangoJSONEncoder),
|
|
actor_id=str(actor.id),
|
|
issue_id=str(issue.id),
|
|
project_id=str(issue.project_id),
|
|
current_instance=None,
|
|
epoch=int(timezone.now().timestamp()),
|
|
notification=True,
|
|
origin=origin,
|
|
)
|
|
return serializer.data
|
|
|
|
|
|
def create_external_contour_notification(*, contour_request, issue, issue_activity_data):
|
|
extra = contour_request.extra or {}
|
|
receiver_id = extra.get("requested_by_id")
|
|
source_project_id = extra.get("source_project_id")
|
|
field = issue_activity_data.get("field")
|
|
actor_id = issue_activity_data.get("actor_id") or (issue_activity_data.get("actor_detail") or {}).get("id")
|
|
|
|
if not receiver_id or not source_project_id or not field:
|
|
return None
|
|
|
|
if field not in EXTERNAL_CONTOUR_NOTIFICATION_FIELDS:
|
|
return None
|
|
|
|
if str(receiver_id) == str(actor_id):
|
|
return None
|
|
|
|
source_project = Project.objects.filter(
|
|
pk=source_project_id,
|
|
workspace_id=issue.workspace_id,
|
|
archived_at__isnull=True,
|
|
).first()
|
|
|
|
if not source_project:
|
|
return None
|
|
|
|
issue_comment = (
|
|
IssueComment.objects.filter(
|
|
id=issue_activity_data.get("issue_comment"),
|
|
issue_id=issue.id,
|
|
project_id=issue.project_id,
|
|
workspace_id=issue.workspace_id,
|
|
).first()
|
|
if issue_activity_data.get("issue_comment")
|
|
else None
|
|
)
|
|
|
|
return Notification(
|
|
workspace=source_project.workspace,
|
|
project=source_project,
|
|
sender=f"in_app:external_contours:{field}",
|
|
triggered_by_id=actor_id,
|
|
receiver_id=receiver_id,
|
|
entity_identifier=issue.id,
|
|
entity_name="issue",
|
|
title=issue_activity_data.get("comment") or "External contour updated",
|
|
data={
|
|
"issue": {
|
|
"id": str(contour_request.id),
|
|
"name": str(issue.name),
|
|
"identifier": str(issue.project.identifier),
|
|
"sequence_id": issue.sequence_id,
|
|
"state_name": issue.state.name if issue.state else None,
|
|
"state_group": issue.state.group if issue.state else None,
|
|
"project_id": str(source_project.id),
|
|
"workspace_slug": str(source_project.workspace.slug),
|
|
"external_contour_request_id": str(contour_request.id),
|
|
"target_issue_id": str(issue.id),
|
|
"target_project_id": str(issue.project_id),
|
|
"target_project_name": str(issue.project.name),
|
|
"source_project_id": str(source_project.id),
|
|
"source_project_name": str(source_project.name),
|
|
},
|
|
"issue_activity": {
|
|
"id": str(issue_activity_data.get("id")),
|
|
"verb": str(issue_activity_data.get("verb")),
|
|
"field": str(field),
|
|
"actor": str(actor_id),
|
|
"new_value": str(issue_activity_data.get("new_value")),
|
|
"old_value": str(issue_activity_data.get("old_value")),
|
|
"issue_comment": str(issue_comment.comment_stripped if issue_comment is not None else ""),
|
|
"old_identifier": (
|
|
str(issue_activity_data.get("old_identifier")) if issue_activity_data.get("old_identifier") else None
|
|
),
|
|
"new_identifier": (
|
|
str(issue_activity_data.get("new_identifier")) if issue_activity_data.get("new_identifier") else None
|
|
),
|
|
},
|
|
},
|
|
)
|