Skip to content

Commit

Permalink
improvement(highlights): send notification to action item assignee
Browse files Browse the repository at this point in the history
When assigning action item in Highlights Widget,
assignee will get Argus Notification with
link to the view and action details.

closes: scylladb#500
  • Loading branch information
soyacz committed Dec 21, 2024
1 parent f0a284b commit 707c090
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 7 deletions.
6 changes: 4 additions & 2 deletions argus/backend/controller/views_widgets/highlights.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from dataclasses import dataclass, asdict
from datetime import datetime, UTC
from dataclasses import asdict
from uuid import UUID

from flask import Blueprint, request, g
Expand Down Expand Up @@ -80,6 +79,9 @@ def set_assignee():
payload = HighlightSetAssignee(**get_payload(request))
service = HighlightsService()
updated_action_item = service.set_assignee(payload)
if payload.assignee_id:
service.send_action_notification(sender_id=g.user.id, username=g.user.username, view_id=payload.view_id,
assignee_id=payload.assignee_id, action=updated_action_item.content)
return {"status": "ok", "response": asdict(updated_action_item)}


Expand Down
2 changes: 2 additions & 0 deletions argus/backend/models/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,14 @@ class ArgusNotificationTypes(str, Enum):
StatusChange = "TYPE_STATUS_CHANGE"
AssigneeChange = "TYPE_ASSIGNEE_CHANGE"
ScheduleChange = "TYPE_SCHEDULE_CHANGE"
ViewActionItemAssignee = "TYPE_VIEW_ACTION_ITEM_ASSIGNEE"


class ArgusNotificationSourceTypes(str, Enum):
TestRun = "TEST_RUN"
Schedule = "SCHEDULE"
Comment = "COMMENT"
ViewActionItem = "VIEW_ACTION_ITEM"


class ArgusNotificationState(IntEnum):
Expand Down
4 changes: 4 additions & 0 deletions argus/backend/service/notification_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class NotificationSenderBase:
ArgusNotificationTypes.StatusChange: "A run you are assigned to changed status",
ArgusNotificationTypes.AssigneeChange: "You were assigned to a run",
ArgusNotificationTypes.ScheduleChange: "You were assigned to a schedule",
ArgusNotificationTypes.ViewActionItemAssignee: "You were assigned to a view action item",
}

CONTENT_TEMPLATES = {}
Expand Down Expand Up @@ -95,6 +96,8 @@ class ArgusDBNotificationSaver(NotificationSenderBase):
CONTENT_TEMPLATES = {
ArgusNotificationTypes.Mention: lambda p: render_template("notifications/mention.html.j2", **p if p else {}),
ArgusNotificationTypes.AssigneeChange: lambda p: render_template("notifications/assigned.html.j2", **p if p else {}),
ArgusNotificationTypes.ViewActionItemAssignee: lambda p: render_template(
"notifications/view_action_item_assigned.html.j2", **p if p else {}),
}

def send_notification(self, receiver: UUID, sender: UUID, notification_type: ArgusNotificationTypes, source_type: ArgusNotificationSourceTypes,
Expand All @@ -120,6 +123,7 @@ class EmailNotificationServiceSender(NotificationSenderBase):
ArgusNotificationTypes.Mention: lambda p: render_template(
"notifications/email_mention.html.j2", **p if p else {}),
ArgusNotificationTypes.AssigneeChange: lambda p: render_template("notifications/assigned_email.html.j2", **p if p else {}),
ArgusNotificationTypes.ViewActionItemAssignee: lambda p: render_template("notifications/view_action_item_assigned_email.html.j2", **p if p else {}),
}

def __init__(self):
Expand Down
30 changes: 27 additions & 3 deletions argus/backend/service/views_widgets/highlights.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from argus.backend.db import ScyllaCluster
from argus.backend.models.view_widgets import WidgetHighlights, WidgetComment
from argus.backend.models.web import ArgusNotificationTypes, ArgusNotificationSourceTypes, ArgusUserView
from argus.backend.service.notification_manager import NotificationManagerService


@dataclass
Expand Down Expand Up @@ -71,13 +73,15 @@ class CommentUpdate:
created_at: float
content: str


@dataclass
class CommentDelete:
view_id: UUID
index: int
highlight_created_at: float
created_at: float


@dataclass
class Comment:
view_id: UUID
Expand Down Expand Up @@ -129,8 +133,11 @@ class HighlightSetAssignee:
view_id: UUID
index: int
created_at: float
assignee_id: str | None = None
assignee_id: UUID | None = None

def __post_init__(self):
if self.assignee_id and not isinstance(self.assignee_id, UUID):
self.assignee_id = UUID(self.assignee_id)

@dataclass
class HighlightSetCompleted:
Expand Down Expand Up @@ -174,7 +181,7 @@ def archive_highlight(self, payload: HighlightArchive):
entry.archived_at = datetime.now(UTC)
entry.save()

def unarchive_highlight(self, payload: HighlightArchive):
def unarchive_highlight(self, payload: HighlightArchive):
entry = WidgetHighlights.objects(
view_id=payload.view_id,
index=payload.index,
Expand Down Expand Up @@ -212,7 +219,7 @@ def set_assignee(self, payload: HighlightSetAssignee) -> ActionItem:
if payload.assignee_id is None:
entry.assignee_id = None
else:
entry.assignee_id = UUID(payload.assignee_id)
entry.assignee_id = payload.assignee_id
entry.save()
return ActionItem.from_db_model(entry)

Expand Down Expand Up @@ -295,3 +302,20 @@ def get_comments(self, view_id: UUID, index: int, highlight_created_at: float) -
highlight_created_at = datetime.fromtimestamp(highlight_created_at, tz=UTC)
comments = WidgetComment.objects(view_id=view_id, index=index, highlight_at=highlight_created_at)
return [Comment.from_db_model(c) for c in comments]

def send_action_notification(self, sender_id: UUID, username: str, view_id: UUID, assignee_id: UUID, action: str):
view = ArgusUserView.get(id=view_id)
NotificationManagerService().send_notification(
receiver=assignee_id,
sender=sender_id,
notification_type=ArgusNotificationTypes.ViewActionItemAssignee,
source_type=ArgusNotificationSourceTypes.ViewActionItem,
source_id=view_id,
source_message="",
content_params={
"username": username,
"view_name": view.name,
"display_name": view.display_name,
"action": action,
}
)
6 changes: 4 additions & 2 deletions argus/backend/tests/view_widgets/test_highlights_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from datetime import datetime, UTC
from unittest.mock import patch
from uuid import uuid4, UUID

from flask import g
Expand Down Expand Up @@ -303,8 +304,8 @@ def test_set_completed_should_not_work_for_highlight(flask_client):
assert response.json["status"] == "error"
assert response.json["response"]["exception"] == "NotFound"


def test_set_assignee_should_set_assignee_for_action_item(flask_client):
@patch("argus.backend.controller.views_widgets.highlights.HighlightsService.send_action_notification")
def test_set_assignee_should_set_assignee_for_action_item(notification, flask_client):
view_id = str(uuid4())
created_at = datetime.now(UTC)
action_item_entry = WidgetHighlights(
Expand Down Expand Up @@ -333,6 +334,7 @@ def test_set_assignee_should_set_assignee_for_action_item(flask_client):
assert response.status_code == 200
assert response.json["status"] == "ok"
assert response.json["response"]["assignee_id"] == new_assignee_id
assert notification.call_count == 1

updated_entry = WidgetHighlights.objects(view_id=UUID(view_id), index=0, created_at=created_at).first()
assert str(updated_entry.assignee_id) == new_assignee_id
Expand Down
3 changes: 3 additions & 0 deletions templates/notifications/view_action_item_assigned.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
You were assigned by <span class='fw-bold'>@{{ username }}</span> to View Action <a
href='{{ url_for("main.view_dashboard", **{ "view_name": view_name}) }}'>{{ display_name }}</a>.
<p>Action: {{ action }}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>You were assigned by <span style="font-weight:bold">@{{ username }}</span> to View Action<a href='
{{ config["BASE_URL"] }}{{ url_for("main.view_dashboard", **{ "view_name": view_name}) }}'>{{ display_name }}</a>.
<p>Action: {{ action }}</p>
</div>

0 comments on commit 707c090

Please sign in to comment.