From e140423362a6fa6ad2ccd633b0e5eb440cfcd78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Tue, 24 Oct 2023 10:16:52 +0200 Subject: [PATCH] feat(notifications): u#3207 notify when a story has been deleted --- .../stories/stories/notifications/__init__.py | 27 ++++++++++++++++++- .../stories/stories/notifications/content.py | 9 +++++++ .../stories/stories/services/__init__.py | 9 ++++--- .../taiga/stories/stories/test_services.py | 17 +++++++----- 4 files changed, 52 insertions(+), 10 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 5c408cc76..173656281 100644 --- a/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py +++ b/python/apps/taiga/src/taiga/stories/stories/notifications/__init__.py @@ -7,10 +7,14 @@ from taiga.notifications import services as notifications_services from taiga.stories.stories.models import Story -from taiga.stories.stories.notifications.content import StoryStatusChangeNotificationContent +from taiga.stories.stories.notifications.content import ( + StoryDeleteNotificationContent, + StoryStatusChangeNotificationContent, +) from taiga.users.models import User STORIES_STATUS_CHANGE = "stories.status_change" +STORIES_DELETE = "stories.delete" async def notify_when_story_status_change(story: Story, status: str, emitted_by: User) -> None: @@ -33,3 +37,24 @@ async def notify_when_story_status_change(story: Story, status: str, emitted_by: status=status, ), ) + + +async def notify_when_story_is_deleted(story: Story, emitted_by: User) -> None: + """ + Emit notification when a story is deleted + """ + notified_users = set() + if story.created_by: + notified_users.add(story.created_by) + notified_users.discard(emitted_by) + + await notifications_services.notify_users( + type=STORIES_DELETE, + emitted_by=emitted_by, + notified_users=notified_users, + content=StoryDeleteNotificationContent( + projects=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 322bb20e2..e1358f976 100644 --- a/python/apps/taiga/src/taiga/stories/stories/notifications/content.py +++ b/python/apps/taiga/src/taiga/stories/stories/notifications/content.py @@ -11,6 +11,15 @@ from taiga.users.serializers.nested import UserNestedSerializer +class StoryDeleteNotificationContent(BaseModel): + projects: ProjectLinkNestedSerializer + story: StoryNestedSerializer + deleted_by: UserNestedSerializer + + class Config: + orm_mode = True + + class StoryStatusChangeNotificationContent(BaseModel): projects: ProjectLinkNestedSerializer story: StoryNestedSerializer 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 760008326..5d512d38d 100644 --- a/python/apps/taiga/src/taiga/stories/stories/services/__init__.py +++ b/python/apps/taiga/src/taiga/stories/stories/services/__init__.py @@ -20,7 +20,7 @@ from taiga.stories.stories.serializers import ReorderStoriesSerializer, StoryDetailSerializer, StorySummarySerializer from taiga.stories.stories.serializers import services as serializers_services from taiga.stories.stories.services import exceptions as ex -from taiga.users.models import AnyUser, User +from taiga.users.models import User from taiga.workflows import repositories as workflows_repositories from taiga.workflows.models import Workflow, WorkflowStatus @@ -391,12 +391,15 @@ async def _calculate_next_order(status_id: UUID) -> Decimal: ########################################################## -async def delete_story(story: Story, deleted_by: AnyUser) -> bool: +async def delete_story(story: Story, deleted_by: User) -> bool: deleted = await stories_repositories.delete_stories(filters={"id": story.id}) if deleted > 0: await stories_events.emit_event_when_story_is_deleted( project=story.project, ref=story.ref, deleted_by=deleted_by ) + await stories_notifications.notify_when_story_is_deleted( + story=story, + emitted_by=deleted_by, + ) return True - return False 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 3e4ad3806..b7b3666a0 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 @@ -793,14 +793,17 @@ async def test_delete_story_fail(): with ( patch("taiga.stories.stories.services.stories_repositories", autospec=True) as fake_story_repo, patch("taiga.stories.stories.services.stories_events", autospec=True) as fake_stories_events, + patch("taiga.stories.stories.services.stories_notifications", autospec=True) as fake_notifications, ): fake_story_repo.delete_stories.return_value = 0 - await services.delete_story(story=story, deleted_by=user) - fake_stories_events.emit_event_when_story_is_deleted.assert_not_awaited() + assert not (await services.delete_story(story=story, deleted_by=user)) + fake_story_repo.delete_stories.assert_awaited_once_with( filters={"id": story.id}, ) + fake_stories_events.emit_event_when_story_is_deleted.assert_not_awaited() + fake_notifications.notify_when_story_is_deleted.assert_not_awaited() async def test_delete_story_ok(): @@ -810,16 +813,18 @@ async def test_delete_story_ok(): with ( patch("taiga.stories.stories.services.stories_repositories", autospec=True) as fake_story_repo, patch("taiga.stories.stories.services.stories_events", autospec=True) as fake_stories_events, + patch("taiga.stories.stories.services.stories_notifications", autospec=True) as fake_notifications, ): fake_story_repo.delete_stories.return_value = 1 - await services.delete_story(story=story, deleted_by=user) - fake_stories_events.emit_event_when_story_is_deleted.assert_awaited_once_with( - project=story.project, ref=story.ref, deleted_by=user - ) + assert await services.delete_story(story=story, deleted_by=user) fake_story_repo.delete_stories.assert_awaited_once_with( filters={"id": story.id}, ) + fake_stories_events.emit_event_when_story_is_deleted.assert_awaited_once_with( + project=story.project, ref=story.ref, deleted_by=user + ) + fake_notifications.notify_when_story_is_deleted.assert_awaited_once_with(story=story, emitted_by=user) #######################################################