From e387f71d7319f93102be254ce2454ea47b6f96bd Mon Sep 17 00:00:00 2001 From: Yamila Moreno Date: Mon, 6 Nov 2023 16:27:29 +0100 Subject: [PATCH] feat(notifications): u#3985 notify when a story has changed workflow (and status) --- .../stories/stories/notifications/__init__.py | 29 +++++++++++++++++-- .../stories/stories/notifications/content.py | 15 ++++++++-- .../stories/stories/services/__init__.py | 9 +++++- .../taiga/stories/stories/test_services.py | 6 +++- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py b/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py index 173656281..4ba5802dd 100644 --- a/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py +++ b/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py @@ -10,10 +10,12 @@ from taiga.stories.stories.notifications.content import ( StoryDeleteNotificationContent, StoryStatusChangeNotificationContent, + StoryWorkflowChangeNotificationContent, ) from taiga.users.models import User STORIES_STATUS_CHANGE = "stories.status_change" +STORIES_WORKFLOW_CHANGE = "stories.workflow_change" STORIES_DELETE = "stories.delete" @@ -31,7 +33,7 @@ async def notify_when_story_status_change(story: Story, status: str, emitted_by: emitted_by=emitted_by, notified_users=notified_users, content=StoryStatusChangeNotificationContent( - projects=story.project, + project=story.project, story=story, changed_by=emitted_by, status=status, @@ -39,6 +41,29 @@ async def notify_when_story_status_change(story: Story, status: str, emitted_by: ) +async def notify_when_story_workflow_change(story: Story, workflow: str, status: str, emitted_by: User) -> None: + """ + Emit notification when a story workflow changes + """ + notified_users = {u async for u in story.assignees.all()} + if story.created_by: + notified_users.add(story.created_by) + notified_users.discard(emitted_by) + + await notifications_services.notify_users( + type=STORIES_WORKFLOW_CHANGE, + emitted_by=emitted_by, + notified_users=notified_users, + content=StoryWorkflowChangeNotificationContent( + project=story.project, + story=story, + changed_by=emitted_by, + workflow=workflow, + status=status, + ), + ) + + async def notify_when_story_is_deleted(story: Story, emitted_by: User) -> None: """ Emit notification when a story is deleted @@ -53,7 +78,7 @@ async def notify_when_story_is_deleted(story: Story, emitted_by: User) -> None: emitted_by=emitted_by, notified_users=notified_users, content=StoryDeleteNotificationContent( - projects=story.project, + project=story.project, story=story, deleted_by=emitted_by, ), diff --git a/python/apps/taiga/src/taiga/stories/stories/notifications/content.py b/python/apps/taiga/src/taiga/stories/stories/notifications/content.py index e1358f976..c922fbf5c 100644 --- a/python/apps/taiga/src/taiga/stories/stories/notifications/content.py +++ b/python/apps/taiga/src/taiga/stories/stories/notifications/content.py @@ -12,7 +12,7 @@ class StoryDeleteNotificationContent(BaseModel): - projects: ProjectLinkNestedSerializer + project: ProjectLinkNestedSerializer story: StoryNestedSerializer deleted_by: UserNestedSerializer @@ -21,10 +21,21 @@ class Config: class StoryStatusChangeNotificationContent(BaseModel): - projects: ProjectLinkNestedSerializer + project: ProjectLinkNestedSerializer story: StoryNestedSerializer changed_by: UserNestedSerializer status: str class Config: orm_mode = True + + +class StoryWorkflowChangeNotificationContent(BaseModel): + project: ProjectLinkNestedSerializer + story: StoryNestedSerializer + changed_by: UserNestedSerializer + status: str + workflow: str + + class Config: + orm_mode = True diff --git a/python/apps/taiga/src/taiga/stories/stories/services/__init__.py b/python/apps/taiga/src/taiga/stories/stories/services/__init__.py index b696030e4..7b7e9e73f 100644 --- a/python/apps/taiga/src/taiga/stories/stories/services/__init__.py +++ b/python/apps/taiga/src/taiga/stories/stories/services/__init__.py @@ -197,7 +197,14 @@ async def update_story( ) # Emit notifications - if "status" in update_values: + if "workflow" in update_values: + await stories_notifications.notify_when_story_workflow_change( + story=story, + workflow=update_values["workflow"].name, + status=update_values["status"].name, + emitted_by=updated_by, + ) + elif "status" in update_values: await stories_notifications.notify_when_story_status_change( story=story, status=update_values["status"].name, diff --git a/python/apps/taiga/tests/unit/taiga/stories/stories/test_services.py b/python/apps/taiga/tests/unit/taiga/stories/stories/test_services.py index b7b3666a0..6542bda06 100644 --- a/python/apps/taiga/tests/unit/taiga/stories/stories/test_services.py +++ b/python/apps/taiga/tests/unit/taiga/stories/stories/test_services.py @@ -250,6 +250,7 @@ async def test_update_story_ok(): updates_attrs=[*values], ) fake_notifications.notify_when_story_status_change.assert_not_awaited() + fake_notifications.notify_when_story_workflow_change.assert_not_awaited() assert updated_story == detailed_story @@ -324,7 +325,8 @@ async def test_update_story_workflow_ok(): updates_attrs=[*values], ) - fake_notifications.notify_when_story_status_change.assert_awaited_once() + fake_notifications.notify_when_story_status_change.assert_not_awaited() + fake_notifications.notify_when_story_workflow_change.assert_awaited_once() async def test_update_story_error_wrong_version(): @@ -365,6 +367,7 @@ async def test_update_story_error_wrong_version(): fake_get_story_detail.assert_not_awaited() fake_stories_events.emit_event_when_story_is_updated.assert_not_awaited() fake_notifications.notify_when_story_status_change.assert_not_awaited() + fake_notifications.notify_when_story_workflow_change.assert_not_awaited() ####################################################### @@ -706,6 +709,7 @@ async def test_reorder_stories_ok(): ) fake_stories_events.emit_when_stories_are_reordered.assert_awaited_once() assert fake_notifications.notify_when_story_status_change.await_count == 3 + assert fake_notifications.notify_when_story_workflow_change.assert_awaited() async def test_reorder_story_workflowstatus_does_not_exist():