From 5eec9dba977cf530ca24df7248d3b8e90aa7adda Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 21 Nov 2016 12:16:46 +0100 Subject: [PATCH] Issue 4768: Notify when something is unassigned --- taiga/projects/notifications/services.py | 32 +++++++++++++-------- tests/integration/test_notifications.py | 36 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index e998d068..42194b41 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -72,14 +72,14 @@ def create_notify_policy_if_not_exists(project, user, level=NotifyLevel.involved model_cls = apps.get_model("notifications", "NotifyPolicy") try: result = model_cls.objects.get_or_create(project=project, - user=user, - defaults={"notify_level": level}) + user=user, + defaults={"notify_level": level}) return result[0] except IntegrityError as e: raise exc.IntegrityError(_("Notify exists for specified user and project")) from e -def analize_object_for_watchers(obj:object, comment:str, user:object): +def analize_object_for_watchers(obj: object, comment: str, user: object): """ Generic implementation for analize model objects and extract mentions from it and add it to watchers. @@ -91,7 +91,6 @@ def analize_object_for_watchers(obj:object, comment:str, user:object): if not hasattr(obj, "add_watcher"): return - texts = (getattr(obj, "description", ""), getattr(obj, "content", ""), comment,) @@ -142,7 +141,7 @@ def get_users_to_notify(obj, *, discard_users=None) -> list: """ project = obj.get_project() - def _check_level(project:object, user:object, levels:tuple) -> bool: + def _check_level(project: object, user: object, levels: tuple) -> bool: policy = project.cached_notify_policy_for_user(user) return policy.notify_level in levels @@ -167,7 +166,7 @@ def get_users_to_notify(obj, *, discard_users=None) -> list: return frozenset(candidates) -def _resolve_template_name(model:object, *, change_type:int) -> str: +def _resolve_template_name(model: object, *, change_type: int) -> str: """ Ginven an changed model instance and change type, return the preformated template name for it. @@ -187,7 +186,7 @@ def _resolve_template_name(model:object, *, change_type:int) -> str: change=change_type) -def _make_template_mail(name:str): +def _make_template_mail(name: str): """ Helper that creates a adhoc djmail template email instance for specified name, and return an instance @@ -211,7 +210,7 @@ def send_notifications(obj, *, history): .get_or_create(key=key, owner=owner, project=obj.project, - history_type = history.type)) + history_type=history.type)) notification.updated_datetime = timezone.now() notification.save() @@ -222,6 +221,14 @@ def send_notifications(obj, *, history): notify_users = get_users_to_notify(obj, discard_users=[notification.owner]) notification.notify_users.add(*notify_users) + # If the history is an unassignment change we should notify that user too + if history.type == HistoryType.change and "assigned_to" in history.diff: + if history.diff["assigned_to"][0] is not None: + notification.notify_users.add(history.diff["assigned_to"][0]) + + if history.diff["assigned_to"][1] is not None: + notification.notify_users.add(history.diff["assigned_to"][1]) + # If we are the min interval is 0 it just work in a synchronous and spamming way if settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL == 0: send_sync_notifications(notification.id) @@ -392,8 +399,11 @@ def add_watcher(obj, user): :param user: User adding the watch. :class:`~taiga.users.models.User` instance. """ obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj) - watched, created = Watched.objects.get_or_create(content_type=obj_type, - object_id=obj.id, user=user, project=obj.project) + watched, created = Watched.objects.get_or_create( + content_type=obj_type, + object_id=obj.id, + user=user, + project=obj.project) notify_policy, _ = apps.get_model("notifications", "NotifyPolicy").objects.get_or_create( project=obj.project, user=user, defaults={"notify_level": NotifyLevel.involved}) @@ -422,7 +432,7 @@ def set_notify_policy_level(notify_policy, notify_level): """ Set notification level for specified policy. """ - if not notify_level in [e.value for e in NotifyLevel]: + if notify_level not in [e.value for e in NotifyLevel]: raise exc.IntegrityError(_("Invalid value for notify level")) notify_policy.notify_level = notify_level diff --git a/tests/integration/test_notifications.py b/tests/integration/test_notifications.py index fd8f3aa8..c49e8a12 100644 --- a/tests/integration/test_notifications.py +++ b/tests/integration/test_notifications.py @@ -726,6 +726,42 @@ def test_send_notifications_using_services_method_for_wiki_pages(settings, mail) assert services.make_ms_thread_index(in_reply_to, msg_ts) == headers.get('Thread-Index') +def test_send_notifications_on_unassigned(client, mail): + project = f.ProjectFactory.create() + role = f.RoleFactory.create(project=project, permissions=['modify_issue', 'view_issues', 'view_us', 'view_tasks', 'view_wiki_pages']) + member1 = f.MembershipFactory.create(project=project, role=role) + member2 = f.MembershipFactory.create(project=project, role=role) + issue = f.IssueFactory.create(project=project, + owner=member1.user, + milestone=None, + status=project.default_issue_status, + severity=project.default_severity, + priority=project.default_priority, + type=project.default_issue_type) + + take_snapshot(issue, user=issue.owner) + + client.login(member1.user) + url = reverse("issues-detail", args=[issue.pk]) + data = { + "assigned_to": member2.user.id, + "version": issue.version + } + response = client.json.patch(url, json.dumps(data)) + assert len(mail.outbox) == 1 + assert mail.outbox[0].to == [member2.user.email] + + mail.outbox = [] + + data = { + "assigned_to": None, + "version": issue.version + 1 + } + response = client.json.patch(url, json.dumps(data)) + assert len(mail.outbox) == 1 + assert mail.outbox[0].to == [member2.user.email] + + def test_resource_notification_test(client, settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1