Merge pull request #883 from taigaio/issue/4768/Notify-when-something-is-unassigned

Issue 4768: Notify when something is unassigned
remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-11-21 18:27:45 +01:00 committed by GitHub
commit c0daa9180f
2 changed files with 57 additions and 11 deletions

View File

@ -72,14 +72,14 @@ def create_notify_policy_if_not_exists(project, user, level=NotifyLevel.involved
model_cls = apps.get_model("notifications", "NotifyPolicy") model_cls = apps.get_model("notifications", "NotifyPolicy")
try: try:
result = model_cls.objects.get_or_create(project=project, result = model_cls.objects.get_or_create(project=project,
user=user, user=user,
defaults={"notify_level": level}) defaults={"notify_level": level})
return result[0] return result[0]
except IntegrityError as e: except IntegrityError as e:
raise exc.IntegrityError(_("Notify exists for specified user and project")) from 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 Generic implementation for analize model objects and
extract mentions from it and add it to watchers. 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"): if not hasattr(obj, "add_watcher"):
return return
texts = (getattr(obj, "description", ""), texts = (getattr(obj, "description", ""),
getattr(obj, "content", ""), getattr(obj, "content", ""),
comment,) comment,)
@ -142,7 +141,7 @@ def get_users_to_notify(obj, *, discard_users=None) -> list:
""" """
project = obj.get_project() 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) policy = project.cached_notify_policy_for_user(user)
return policy.notify_level in levels return policy.notify_level in levels
@ -167,7 +166,7 @@ def get_users_to_notify(obj, *, discard_users=None) -> list:
return frozenset(candidates) 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, Ginven an changed model instance and change type,
return the preformated template name for it. return the preformated template name for it.
@ -187,7 +186,7 @@ def _resolve_template_name(model:object, *, change_type:int) -> str:
change=change_type) change=change_type)
def _make_template_mail(name:str): def _make_template_mail(name: str):
""" """
Helper that creates a adhoc djmail template email Helper that creates a adhoc djmail template email
instance for specified name, and return an instance instance for specified name, and return an instance
@ -211,7 +210,7 @@ def send_notifications(obj, *, history):
.get_or_create(key=key, .get_or_create(key=key,
owner=owner, owner=owner,
project=obj.project, project=obj.project,
history_type = history.type)) history_type=history.type))
notification.updated_datetime = timezone.now() notification.updated_datetime = timezone.now()
notification.save() notification.save()
@ -222,6 +221,14 @@ def send_notifications(obj, *, history):
notify_users = get_users_to_notify(obj, discard_users=[notification.owner]) notify_users = get_users_to_notify(obj, discard_users=[notification.owner])
notification.notify_users.add(*notify_users) 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 we are the min interval is 0 it just work in a synchronous and spamming way
if settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL == 0: if settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL == 0:
send_sync_notifications(notification.id) 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. :param user: User adding the watch. :class:`~taiga.users.models.User` instance.
""" """
obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj) obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj)
watched, created = Watched.objects.get_or_create(content_type=obj_type, watched, created = Watched.objects.get_or_create(
object_id=obj.id, user=user, project=obj.project) content_type=obj_type,
object_id=obj.id,
user=user,
project=obj.project)
notify_policy, _ = apps.get_model("notifications", "NotifyPolicy").objects.get_or_create( notify_policy, _ = apps.get_model("notifications", "NotifyPolicy").objects.get_or_create(
project=obj.project, user=user, defaults={"notify_level": NotifyLevel.involved}) 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. 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")) raise exc.IntegrityError(_("Invalid value for notify level"))
notify_policy.notify_level = notify_level notify_policy.notify_level = notify_level

View File

@ -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') 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): def test_resource_notification_test(client, settings, mail):
settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1