From 6b33c30616d544df2d78d0669809d5c106729482 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:05:08 +0100 Subject: [PATCH 01/10] Fixing notifications __init__ because it was generating migration problems --- taiga/projects/attachments/api.py | 2 +- taiga/projects/issues/api.py | 2 +- taiga/projects/issues/models.py | 2 +- taiga/projects/milestones/api.py | 2 +- taiga/projects/milestones/models.py | 2 +- taiga/projects/notifications/__init__.py | 20 -------------------- taiga/projects/tasks/api.py | 2 +- taiga/projects/tasks/models.py | 2 +- taiga/projects/userstories/api.py | 2 +- taiga/projects/userstories/models.py | 2 +- taiga/projects/wiki/api.py | 2 +- taiga/projects/wiki/models.py | 2 +- 12 files changed, 11 insertions(+), 31 deletions(-) diff --git a/taiga/projects/attachments/api.py b/taiga/projects/attachments/api.py index d54e9aa4..a63b3aa4 100644 --- a/taiga/projects/attachments/api.py +++ b/taiga/projects/attachments/api.py @@ -31,7 +31,7 @@ from taiga.base import filters from taiga.base import exceptions as exc from taiga.users.models import User -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin from . import permissions diff --git a/taiga/projects/issues/api.py b/taiga/projects/issues/api.py index e4701fd9..ab0878f0 100644 --- a/taiga/projects/issues/api.py +++ b/taiga/projects/issues/api.py @@ -30,7 +30,7 @@ from taiga.base import tags from taiga.users.models import User -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.occ import OCCResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin diff --git a/taiga/projects/issues/models.py b/taiga/projects/issues/models.py index e43bace3..35aad2f1 100644 --- a/taiga/projects/issues/models.py +++ b/taiga/projects/issues/models.py @@ -22,7 +22,7 @@ from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ from taiga.projects.occ import OCCModelMixin -from taiga.projects.notifications import WatchedModelMixin +from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.mixins.blocked import BlockedMixin from taiga.base.tags import TaggedMixin diff --git a/taiga/projects/milestones/api.py b/taiga/projects/milestones/api.py index 2d3a3e50..e5c58b76 100644 --- a/taiga/projects/milestones/api.py +++ b/taiga/projects/milestones/api.py @@ -25,7 +25,7 @@ from taiga.base import exceptions as exc from taiga.base.decorators import detail_route from taiga.base.api import ModelCrudViewSet -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin diff --git a/taiga/projects/milestones/models.py b/taiga/projects/milestones/models.py index 899c8616..2e4e9199 100644 --- a/taiga/projects/milestones/models.py +++ b/taiga/projects/milestones/models.py @@ -22,7 +22,7 @@ from django.core.exceptions import ValidationError from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.dicts import dict_sum -from taiga.projects.notifications import WatchedModelMixin +from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.userstories.models import UserStory import itertools diff --git a/taiga/projects/notifications/__init__.py b/taiga/projects/notifications/__init__.py index 5978b735..e69de29b 100644 --- a/taiga/projects/notifications/__init__.py +++ b/taiga/projects/notifications/__init__.py @@ -1,20 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# Copyright (C) 2014 Jesús Espino -# Copyright (C) 2014 David Barragán -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from .mixins import WatchedResourceMixin -from .mixins import WatchedModelMixin - -__all__ = ["WatchedModelMixin", "WatchedResourceMixin"] diff --git a/taiga/projects/tasks/api.py b/taiga/projects/tasks/api.py index 348b4b7f..d3727b78 100644 --- a/taiga/projects/tasks/api.py +++ b/taiga/projects/tasks/api.py @@ -22,7 +22,7 @@ from taiga.base.decorators import list_route from taiga.base.api import ModelCrudViewSet from taiga.projects.models import Project -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.occ import OCCResourceMixin diff --git a/taiga/projects/tasks/models.py b/taiga/projects/tasks/models.py index 9f71dd3b..25225d42 100644 --- a/taiga/projects/tasks/models.py +++ b/taiga/projects/tasks/models.py @@ -21,7 +21,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from taiga.projects.occ import OCCModelMixin -from taiga.projects.notifications import WatchedModelMixin +from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.mixins.blocked import BlockedMixin from taiga.base.tags import TaggedMixin diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index f1a87c9a..f5648fec 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -30,7 +30,7 @@ from taiga.base import exceptions as exc from taiga.base.decorators import list_route from taiga.base.api import ModelCrudViewSet -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.occ import OCCResourceMixin diff --git a/taiga/projects/userstories/models.py b/taiga/projects/userstories/models.py index 77e487eb..d0038441 100644 --- a/taiga/projects/userstories/models.py +++ b/taiga/projects/userstories/models.py @@ -21,7 +21,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from taiga.projects.occ import OCCModelMixin -from taiga.projects.notifications import WatchedModelMixin +from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.mixins.blocked import BlockedMixin from taiga.base.tags import TaggedMixin diff --git a/taiga/projects/wiki/api.py b/taiga/projects/wiki/api.py index 6942e628..9970502d 100644 --- a/taiga/projects/wiki/api.py +++ b/taiga/projects/wiki/api.py @@ -28,7 +28,7 @@ from taiga.base.decorators import list_route from taiga.projects.models import Project from taiga.mdrender.service import render as mdrender -from taiga.projects.notifications import WatchedResourceMixin +from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin from taiga.projects.occ import OCCResourceMixin diff --git a/taiga/projects/wiki/models.py b/taiga/projects/wiki/models.py index bfe926f8..4f8c6f4c 100644 --- a/taiga/projects/wiki/models.py +++ b/taiga/projects/wiki/models.py @@ -19,7 +19,7 @@ from django.contrib.contenttypes import generic from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.utils import timezone -from taiga.projects.notifications import WatchedModelMixin +from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.occ import OCCModelMixin From a68785a380ad941cf91e820174c4c5c31e8a8ddd Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:06:58 +0100 Subject: [PATCH 02/10] Refactoring modify notifications --- settings/common.py | 1 + taiga/projects/history/models.py | 13 +++- taiga/projects/history/services.py | 8 +++ taiga/projects/notifications/mixins.py | 3 +- taiga/projects/notifications/models.py | 26 +++++++- taiga/projects/notifications/services.py | 77 +++++++++++++++++++----- taiga/projects/userstories/api.py | 1 - 7 files changed, 110 insertions(+), 19 deletions(-) diff --git a/settings/common.py b/settings/common.py index c79edb63..3aef9bdf 100644 --- a/settings/common.py +++ b/settings/common.py @@ -332,6 +332,7 @@ TAGS_PREDEFINED_COLORS = ["#fce94f", "#edd400", "#c4a000", "#8ae234", FEEDBACK_ENABLED = True FEEDBACK_EMAIL = "support@taiga.io" +CHANGE_NOTIFICATIONS_MIN_INTERVAL = 30 #seconds # NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE TEST_RUNNER="django.test.runner.DiscoverRunner" diff --git a/taiga/projects/history/models.py b/taiga/projects/history/models.py index ab58b312..ec79f91f 100644 --- a/taiga/projects/history/models.py +++ b/taiga/projects/history/models.py @@ -76,6 +76,18 @@ class HistoryEntry(models.Model): # snapshot. The rest are partial snapshot. is_snapshot = models.BooleanField(default=False) + @cached_property + def is_change(self): + return self.type == HistoryType.change + + @cached_property + def is_create(self): + return self.type == HistoryType.create + + @cached_property + def is_delete(self): + return self.type == HistoryType.delete + @cached_property def owner(self): pk = self.user["pk"] @@ -198,4 +210,3 @@ class HistoryEntry(models.Model): class Meta: ordering = ["created_at"] - diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py index 3401f42a..31e56f99 100644 --- a/taiga/projects/history/services.py +++ b/taiga/projects/history/services.py @@ -73,6 +73,14 @@ def make_key_from_model_object(obj:object) -> str: return "{0}:{1}".format(tn, obj.pk) +def get_model_from_key(key:str) -> object: + """ + Get model from key + """ + class_name, pk = key.split(":", 1) + return apps.get_model(class_name) + + def register_values_implementation(typename:str, fn=None): """ Register values implementation for specified typename. diff --git a/taiga/projects/notifications/mixins.py b/taiga/projects/notifications/mixins.py index f5be6166..362635a4 100644 --- a/taiga/projects/notifications/mixins.py +++ b/taiga/projects/notifications/mixins.py @@ -62,8 +62,7 @@ class WatchedResourceMixin(object): # Get a complete list of notifiable users for current # object and send the change notification to them. - users = services.get_users_to_notify(obj, history=history) - services.send_notifications(obj, history=history, users=users) + services.send_notifications(obj, history=history) def post_save(self, obj, created=False): self.send_notifications(obj) diff --git a/taiga/projects/notifications/models.py b/taiga/projects/notifications/models.py index bdff3d90..1b62ce0a 100644 --- a/taiga/projects/notifications/models.py +++ b/taiga/projects/notifications/models.py @@ -19,7 +19,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from .choices import NOTIFY_LEVEL_CHOICES - +from taiga.projects.history.choices import HISTORY_TYPE_CHOICES class NotifyPolicy(models.Model): """ @@ -43,3 +43,27 @@ class NotifyPolicy(models.Model): self.modified_at = timezone.now() return super().save(*args, **kwargs) + + +class HistoryChangeNotification(models.Model): + """ + This class controls the pending notifications for an object, it should be instantiated + or updated when an object requires notifications. + """ + key = models.CharField(max_length=255, unique=False, editable=False) + owner = models.ForeignKey("users.User", null=False, blank=False, + verbose_name="owner",related_name="+") + created_datetime = models.DateTimeField(null=False, blank=False, auto_now_add=True, + verbose_name=_("created date time")) + updated_datetime = models.DateTimeField(null=False, blank=False, auto_now_add=True, + verbose_name=_("updated date time")) + history_entries = models.ManyToManyField("history.HistoryEntry", null=True, blank=True, + verbose_name="history entries", + related_name="+") + notify_users = models.ManyToManyField("users.User", null=True, blank=True, + verbose_name="notify users", + related_name="+") + project = models.ForeignKey("projects.Project", null=False, blank=False, + verbose_name="project",related_name="+") + + history_type = models.SmallIntegerField(choices=HISTORY_TYPE_CHOICES) diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index 1b8c86c0..746beace 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -19,6 +19,9 @@ from functools import partial from django.apps import apps from django.db import IntegrityError from django.contrib.contenttypes.models import ContentType +from django.utils import timezone +from django.db import transaction +from django.conf import settings from djmail import template_mail @@ -26,7 +29,12 @@ from taiga.base import exceptions as exc from taiga.base.utils.text import strip_lines from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.history.choices import HistoryType +from taiga.projects.history.services import (make_key_from_model_object, + get_last_snapshot_for_key, + get_model_from_key) +from taiga.users.models import User +from .models import HistoryChangeNotification def notify_policy_exists(project, user) -> bool: """ @@ -113,7 +121,7 @@ def analize_object_for_watchers(obj:object, history:object): obj.watchers.add(user) -def get_users_to_notify(obj, *, history) -> list: +def get_users_to_notify(obj, *, discard_users=None) -> list: """ Get filtered set of users to notify for specified model instance and changer. @@ -138,18 +146,18 @@ def get_users_to_notify(obj, *, history) -> list: candidates.update(filter(_can_notify_light, obj.get_participants())) # Remove the changer from candidates - candidates.discard(history.owner) + if discard_users: + candidates = candidates - set(discard_users) return frozenset(candidates) -def _resolve_template_name(obj, *, 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. """ - ct = ContentType.objects.get_for_model(obj.__class__) - + ct = ContentType.objects.get_for_model(model) # Resolve integer enum value from "change_type" # parameter to human readable string if change_type == HistoryType.create: @@ -158,7 +166,6 @@ def _resolve_template_name(obj, *, change_type:int) -> str: change_type = "change" else: change_type = "delete" - tmpl = "{app_label}/{model}-{change}" return tmpl.format(app_label=ct.app_label, model=ct.model, @@ -178,19 +185,61 @@ def _make_template_mail(name:str): return cls() -def send_notifications(obj, *, history, users): +@transaction.atomic +def send_notifications(obj, *, history): + key = make_key_from_model_object(obj) + owner = User.objects.get(pk=history.user["pk"]) + notification, created = (HistoryChangeNotification.objects.select_for_update() + .get_or_create(key=key, + owner=owner, + project=obj.project, + history_type = history.type)) + + notification.updated_datetime = timezone.now() + notification.save() + notification.history_entries.add(history) + + # Get a complete list of notifiable users for current + # object and send the change notification to them. + notify_users = get_users_to_notify(obj, discard_users=[notification.owner]) + for notify_user in notify_users: + notification.notify_users.add(notify_user) + + +@transaction.atomic +def send_sync_notifications(notification_id): """ - Given changed instance, history entry and + Given changed instance, calculate the history entry and a complete list for users to notify, send email to all users. """ - context = {"object": obj, - "changer": history.owner, - "comment": history.comment, - "changed_fields": history.values_diff} - template_name = _resolve_template_name(obj, change_type=history.type) + notification = HistoryChangeNotification.objects.select_for_update().get(pk=notification_id) + # If the las modification is too recent we ignore it + now = timezone.now() + time_diff = now - notification.updated_datetime + if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL: + print(time_diff.seconds) + return + + history_entries = tuple(notification.history_entries.all().order_by("created_at")) + obj, _ = get_last_snapshot_for_key(notification.key) + + context = {"snapshot": obj.snapshot, + "project": notification.project, + "changer": notification.owner, + "history_entries": history_entries} + + model = get_model_from_key(notification.key) + template_name = _resolve_template_name(model, change_type=notification.history_type) email = _make_template_mail(template_name) - for user in users: + for user in notification.notify_users.distinct(): email.send(user.email, context) + + notification.delete() + + +def process_sync_notifications(): + for notification in HistoryChangeNotification.objects.all(): + send_sync_notifications(notification.pk) diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index f5648fec..c1120ff9 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -177,4 +177,3 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi self.send_notifications(self.object.generated_from_issue, history) return response - From 89b8dfdc636ece39a4205fa3a5bbb6b5d72ef6bd Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:02:46 +0100 Subject: [PATCH 03/10] Refactoring email templates for notifications --- .../emails/includes/fields_diff-html.jinja | 4 +-- .../issues/issue-change-body-html.jinja | 26 ++++++++++--------- .../issues/issue-change-body-text.jinja | 24 +++++++++-------- .../emails/issues/issue-change-subject.jinja | 2 +- .../issues/issue-create-body-html.jinja | 8 +++--- .../issues/issue-create-body-text.jinja | 8 +++--- .../emails/issues/issue-create-subject.jinja | 2 +- .../issues/issue-delete-body-html.jinja | 4 +-- .../issues/issue-delete-body-text.jinja | 4 +-- .../emails/issues/issue-delete-subject.jinja | 2 +- .../milestone-change-body-html.jinja | 24 +++++++++-------- .../milestone-change-body-text.jinja | 24 +++++++++-------- .../milestones/milestone-change-subject.jinja | 2 +- .../milestone-create-body-html.jinja | 8 +++--- .../milestone-create-body-text.jinja | 8 +++--- .../milestones/milestone-create-subject.jinja | 2 +- .../milestone-delete-body-html.jinja | 4 +-- .../milestone-delete-body-text.jinja | 4 +-- .../milestones/milestone-delete-subject.jinja | 2 +- .../projects/project-change-body-html.jinja | 22 +++++++++------- .../projects/project-change-body-text.jinja | 25 +++++++++--------- .../projects/project-change-subject.jinja | 2 +- .../projects/project-create-body-html.jinja | 8 +++--- .../projects/project-create-body-text.jinja | 6 ++--- .../projects/project-create-subject.jinja | 2 +- .../projects/project-delete-body-html.jinja | 2 +- .../projects/project-delete-body-text.jinja | 2 +- .../projects/project-delete-subject.jinja | 2 +- .../emails/tasks/task-change-body-html.jinja | 24 +++++++++-------- .../emails/tasks/task-change-body-text.jinja | 24 +++++++++-------- .../emails/tasks/task-change-subject.jinja | 2 +- .../emails/tasks/task-create-body-html.jinja | 8 +++--- .../emails/tasks/task-create-body-text.jinja | 8 +++--- .../emails/tasks/task-create-subject.jinja | 2 +- .../emails/tasks/task-delete-body-html.jinja | 4 +-- .../emails/tasks/task-delete-body-text.jinja | 4 +-- .../emails/tasks/task-delete-subject.jinja | 2 +- .../userstory-change-body-html.jinja | 24 +++++++++-------- .../userstory-change-body-text.jinja | 24 +++++++++-------- .../userstory-change-subject.jinja | 2 +- .../userstory-create-body-html.jinja | 8 +++--- .../userstory-create-body-text.jinja | 8 +++--- .../userstory-create-subject.jinja | 2 +- .../userstory-delete-body-html.jinja | 4 +-- .../userstory-delete-body-text.jinja | 4 +-- .../userstory-delete-subject.jinja | 2 +- .../wiki/wikipage-change-body-html.jinja | 24 +++++++++-------- .../wiki/wikipage-change-body-text.jinja | 24 +++++++++-------- .../emails/wiki/wikipage-change-subject.jinja | 2 +- .../wiki/wikipage-create-body-html.jinja | 8 +++--- .../wiki/wikipage-create-body-text.jinja | 8 +++--- .../emails/wiki/wikipage-create-subject.jinja | 2 +- .../wiki/wikipage-delete-body-html.jinja | 4 +-- .../wiki/wikipage-delete-body-text.jinja | 4 +-- .../emails/wiki/wikipage-delete-subject.jinja | 2 +- 55 files changed, 245 insertions(+), 222 deletions(-) diff --git a/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja b/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja index 049bf6cc..150269b7 100644 --- a/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja +++ b/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja @@ -99,12 +99,12 @@ {# DESCRIPTIONS #} {% elif field_name in ["description_diff"] %}
- diff: {{ mdrender(object.project, values.1) }} + diff: {{ mdrender(project, values.1) }}
{# CONTENT #} {% elif field_name in ["content_diff"] %}
- diff: {{ mdrender(object.project, values.1) }} + diff: {{ mdrender(project, values.1) }}
{# ASSIGNED TO #} {% elif field_name == "assigned_to" %} diff --git a/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja b/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja index 11ddedb5..0f517727 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja @@ -1,23 +1,25 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("issue", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View issue #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("issue", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View issue #{0}".format(snapshot.ref) %} {% block body %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ mdrender(project, entry.comment) }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + + {% endfor %}
-

Project: {{ object.project.name }}

-

Issue #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

Issue #{{ snapshot.ref }}: {{ snapshot.subject }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ mdrender(object.project, comment) }}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} -
{% endblock %} diff --git a/taiga/projects/notifications/templates/emails/issues/issue-change-body-text.jinja b/taiga/projects/notifications/templates/emails/issues/issue-change-body-text.jinja index a3dd43ba..efcd3214 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-change-body-text.jinja @@ -1,15 +1,17 @@ -{% set final_url = resolve_front_url("issue", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View issue #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("issue", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View issue #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- Issue #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- Issue #{{ snapshot.ref }}: {{ snapshot.subject }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% include "emails/includes/fields_diff-text.jinja" %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-text.jinja" %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/issues/issue-change-subject.jinja b/taiga/projects/notifications/templates/emails/issues/issue-change-subject.jinja index 91d2a97f..e6f72cb8 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-change-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Updated the issue #{{ object.ref|safe }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Updated the issue #{{ snapshot.ref|safe }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/issues/issue-create-body-html.jinja b/taiga/projects/notifications/templates/emails/issues/issue-create-body-html.jinja index 29dc64e5..5f6538b8 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-create-body-html.jinja @@ -1,14 +1,14 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("issue", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View issue #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("issue", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View issue #{0}".format(snapshot.ref) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/issues/issue-create-body-text.jinja b/taiga/projects/notifications/templates/emails/issues/issue-create-body-text.jinja index 257e41cf..f64a3176 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-create-body-text.jinja @@ -1,8 +1,8 @@ -{% set final_url = resolve_front_url("issue", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View issue #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("issue", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View issue #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- US #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- US #{{ snapshot.ref }}: {{ snapshot.subject }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/issues/issue-create-subject.jinja b/taiga/projects/notifications/templates/emails/issues/issue-create-subject.jinja index c88820da..93ea5b7d 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-create-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Created the issue #{{ object.ref|safe }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Created the issue #{{ snapshot.ref|safe }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/issues/issue-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/issues/issue-delete-body-html.jinja index d25575a9..d9be80bc 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-delete-body-html.jinja @@ -4,8 +4,8 @@
-

Project: {{ object.project.name }}

-

Issue #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

Issue #{{ snapshot.ref }}: {{ snapshot.subject }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/issues/issue-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/issues/issue-delete-body-text.jinja index 8bf2b9e9..e71c0580 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-delete-body-text.jinja @@ -1,3 +1,3 @@ -- Project: {{ object.project.name }} -- Issue #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- Issue #{{ snapshot.ref }}: {{ snapshot.subject }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/issues/issue-delete-subject.jinja b/taiga/projects/notifications/templates/emails/issues/issue-delete-subject.jinja index e958318e..87d1c86a 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-delete-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Deleted the issue #{{ object.ref|safe }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Deleted the issue #{{ snapshot.ref|safe }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-html.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-html.jinja index ea456b34..898c8e78 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-html.jinja @@ -1,22 +1,24 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("taskboard", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View milestone #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("taskboard", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View milestone #{0}".format(snapshot.slug) %} {% block body %}
-

{{ object.project.name }}

-

Issue #{{ object.ref }}: {{ object.subject }}

+

{{ project.name }}

+

Issue #{{ snapshot.ref }}: {{ snapshot.subject }}

Deleted by {{ changer.get_full_name() }}

-

Project: {{ object.project.name }}

-

Milestone #{{ object.slug }}: {{ object.name }}

+

Project: {{ project.name }}

+

Milestone #{{ snapshot.slug }}: {{ snapshot.name }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ comment|linebreaksbr }}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ entry.comment|linebreaksbr }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + {% endfor %}
diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-text.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-text.jinja index c2f667d5..ff4f4ea2 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-change-body-text.jinja @@ -1,15 +1,17 @@ -{% set final_url = resolve_front_url("taskboard", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View milestone #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("taskboard", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View milestone #{0}".format(snapshot.slug) %} -- Project: {{ object.project.name }} -- Milestone #{{ object.slug }}: {{ object.name }} +- Project: {{ project.name }} +- Milestone #{{ snapshot.slug }}: {{ snapshot.name }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% include "emails/includes/fields_diff-text.jinja" %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-text.jinja" %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-change-subject.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-change-subject.jinja index e2b864e7..1249eb83 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-change-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Updated the milestone #{{ object.slug|safe }} "{{ object.name|safe }}" +[{{ project.name|safe }}] Updated the milestone #{{ snapshot.slug|safe }} "{{ snapshot.name|safe }}" diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-html.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-html.jinja index 1470717f..284e98b0 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-html.jinja @@ -1,14 +1,14 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("taskboard", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View milestone #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("taskboard", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View milestone #{0}".format(snapshot.slug) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-text.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-text.jinja index a12024f9..300c8059 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-create-body-text.jinja @@ -1,8 +1,8 @@ -{% set final_url = resolve_front_url("taskboard", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View milestone #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("taskboard", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View milestone #{0}".format(snapshot.slug) %} -- Project: {{ object.project.name }} -- Milestone #{{ object.slug }}: {{ object.name }} +- Project: {{ project.name }} +- Milestone #{{ snapshot.slug }}: {{ snapshot.name }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-create-subject.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-create-subject.jinja index 176713df..28704d3e 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-create-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Created the milestone #{{ object.slug|safe }} "{{ object.name|safe }}" +[{{ project.name|safe }}] Created the milestone #{{ snapshot.slug|safe }} "{{ snapshot.name|safe }}" diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-html.jinja index d22cbdd4..20ac2a5d 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-html.jinja @@ -4,8 +4,8 @@
-

Project: {{ object.project.name }}

-

Milestone #{{ object.slug }}: {{ object.name }}

+

Project: {{ project.name }}

+

Milestone #{{ snapshot.slug }}: {{ snapshot.name }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-text.jinja index 9298a196..2916ae80 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-body-text.jinja @@ -1,3 +1,3 @@ -- Project: {{ object.project.name }} -- Milestone #{{ object.slug }}: {{ object.name }} +- Project: {{ project.name }} +- Milestone #{{ snapshot.slug }}: {{ snapshot.name }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-subject.jinja b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-subject.jinja index 6bf4b9cf..54221a8c 100644 --- a/taiga/projects/notifications/templates/emails/milestones/milestone-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/milestones/milestone-delete-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Deleted the milestone #{{ object.slug|safe }} "{{ object.name|safe }}" +[{{ project.name|safe }}] Deleted the milestone #{{ snapshot.slug|safe }} "{{ snapshot.name|safe }}" diff --git a/taiga/projects/notifications/templates/emails/projects/project-change-body-html.jinja b/taiga/projects/notifications/templates/emails/projects/project-change-body-html.jinja index 39fe4f7e..0c65ef64 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-change-body-html.jinja @@ -1,21 +1,23 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("project-admin", object.slug) %} -{% set final_url_name = "Taiga - View Project #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("project-admin", snapshot.slug) %} +{% set final_url_name = "Taiga - View Project #{0}".format(snapshot.slug) %} {% block body %}
-

{{ object.project.name }}

-

Milestone #{{ object.slug }}: {{ object.name }}

+

{{ project.name }}

+

Milestone #{{ snapshot.slug }}: {{ snapshot.name }}

Deleted by {{ changer.get_full_name() }}

-

Project #{{ object.slug }}: {{ object.name }}

+

Project #{{ snapshot.slug }}: {{ snapshot.name }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ comment|linebreaksbr }}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ entry.comment|linebreaksbr }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + {% endfor %}
diff --git a/taiga/projects/notifications/templates/emails/projects/project-change-body-text.jinja b/taiga/projects/notifications/templates/emails/projects/project-change-body-text.jinja index dfe93b9c..14fda13f 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-change-body-text.jinja @@ -1,16 +1,17 @@ -{% set final_url = resolve_front_url("project-admin", object.slug) %} -{% set final_url_name = "Taiga - View Project #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("project-admin", snapshot.slug) %} +{% set final_url_name = "Taiga - View Project #{0}".format(snapshot.slug) %} -- Project #{{ object.slug }}: {{ object.name }} +- Project #{{ snapshot.slug }}: {{ snapshot.name }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% for field_name, values in changed_fields.items() %} - * {{ verbose_name(object, field_name) }}: from '{{ values.0 }}' to '{{ values.1 }}'. - {% endfor %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% for field_name, values in changed_fields.items() %} + * {{ verbose_name(object, field_name) }}: from '{{ values.0 }}' to '{{ values.1 }}'. + {% endfor %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/projects/project-change-subject.jinja b/taiga/projects/notifications/templates/emails/projects/project-change-subject.jinja index f2845743..25d9943b 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-change-subject.jinja @@ -1 +1 @@ -[{{ object.name|safe }}] Updated the project #{{ object.slug|safe }} +[{{ snapshot.name|safe }}] Updated the project #{{ snapshot.slug|safe }} diff --git a/taiga/projects/notifications/templates/emails/projects/project-create-body-html.jinja b/taiga/projects/notifications/templates/emails/projects/project-create-body-html.jinja index a45dbab3..a37f59c1 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-create-body-html.jinja @@ -1,12 +1,12 @@ -{% set final_url = resolve_front_url("project-admin", object.slug) %} -{% set final_url_name = "Taiga - View Project #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("project-admin", snapshot.slug) %} +{% set final_url_name = "Taiga - View Project #{0}".format(snapshot.slug) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/projects/project-create-body-text.jinja b/taiga/projects/notifications/templates/emails/projects/project-create-body-text.jinja index af278212..c66430fc 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-create-body-text.jinja @@ -1,7 +1,7 @@ -{% set final_url = resolve_front_url("project-admin", object.slug) %} -{% set final_url_name = "Taiga - View Project #{0}".format(object.slug) %} +{% set final_url = resolve_front_url("project-admin", snapshot.slug) %} +{% set final_url_name = "Taiga - View Project #{0}".format(snapshot.slug) %} -- Project #{{ object.slug }}: {{ object.name }} +- Project #{{ snapshot.slug }}: {{ snapshot.name }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/projects/project-create-subject.jinja b/taiga/projects/notifications/templates/emails/projects/project-create-subject.jinja index 82b06b70..06ed271b 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-create-subject.jinja @@ -1 +1 @@ -[{{ object.name|safe }}] Created the project #{{ object.slug|safe }} +[{{ snapshot.name|safe }}] Created the project #{{ snapshot.slug|safe }} diff --git a/taiga/projects/notifications/templates/emails/projects/project-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/projects/project-delete-body-html.jinja index 09448adc..2b8fa57d 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-delete-body-html.jinja @@ -4,7 +4,7 @@
-

Project: {{ object.project.name }}

-

Project #{{ object.slug }}: {{ object.name }}

+

Project: {{ project.name }}

+

Project #{{ snapshot.slug }}: {{ snapshot.name }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/projects/project-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/projects/project-delete-body-text.jinja index 75d8013b..39935515 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-delete-body-text.jinja @@ -1,2 +1,2 @@ -- Project #{{ object.slug }}: {{ object.name }} +- Project #{{ snapshot.slug }}: {{ snapshot.name }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/projects/project-delete-subject.jinja b/taiga/projects/notifications/templates/emails/projects/project-delete-subject.jinja index 3caf2ac4..cf0adf31 100644 --- a/taiga/projects/notifications/templates/emails/projects/project-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/projects/project-delete-subject.jinja @@ -1 +1 @@ -[{{ object.name|safe }}] Deleted the project #{{ object.slug|safe }} +[{{ snapshot.name|safe }}] Deleted the project #{{ snapshot.slug|safe }} diff --git a/taiga/projects/notifications/templates/emails/tasks/task-change-body-html.jinja b/taiga/projects/notifications/templates/emails/tasks/task-change-body-html.jinja index 1a655513..02bfee38 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-change-body-html.jinja @@ -1,22 +1,24 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("task", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View task #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("task", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View task #{0}".format(snapshot.ref) %} {% block body %}
-

Project #{{ object.slug }}: {{ object.name }}

+

Project #{{ snapshot.slug }}: {{ snapshot.name }}

Deleted by {{ changer.get_full_name() }}

-

Project: {{ object.project.name }}

-

Task #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

Task #{{ snapshot.ref }}: {{ snapshot.subject }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ mdrender(object.project, comment) }}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ mdrender(project, entry.comment) }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + {% endfor %}
diff --git a/taiga/projects/notifications/templates/emails/tasks/task-change-body-text.jinja b/taiga/projects/notifications/templates/emails/tasks/task-change-body-text.jinja index 771d1d94..925fbacc 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-change-body-text.jinja @@ -1,15 +1,17 @@ -{% set final_url = resolve_front_url("task", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View task #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("task", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View task #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- Task #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- Task #{{ snapshot.ref }}: {{ snapshot.subject }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% include "emails/includes/fields_diff-text.jinja" %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-text.jinja" %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/tasks/task-change-subject.jinja b/taiga/projects/notifications/templates/emails/tasks/task-change-subject.jinja index 1074e93b..ddd26e48 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-change-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Updated the task #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Updated the task #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/tasks/task-create-body-html.jinja b/taiga/projects/notifications/templates/emails/tasks/task-create-body-html.jinja index e4122675..6d2a216e 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-create-body-html.jinja @@ -1,14 +1,14 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("task", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View task #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("task", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View task #{0}".format(snapshot.ref) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/tasks/task-create-body-text.jinja b/taiga/projects/notifications/templates/emails/tasks/task-create-body-text.jinja index 231473be..7ceca7fe 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-create-body-text.jinja @@ -1,8 +1,8 @@ -{% set final_url = resolve_front_url("task", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View task #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("task", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View task #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- Task #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- Task #{{ snapshot.ref }}: {{ snapshot.subject }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/tasks/task-create-subject.jinja b/taiga/projects/notifications/templates/emails/tasks/task-create-subject.jinja index 70c37be2..c83009d4 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-create-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Created the task #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Created the task #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/tasks/task-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/tasks/task-delete-body-html.jinja index 008ff424..0186fa98 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-delete-body-html.jinja @@ -4,8 +4,8 @@
-

Project: {{ object.project.name }}

-

Task #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

Task #{{ snapshot.ref }}: {{ snapshot.subject }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/tasks/task-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/tasks/task-delete-body-text.jinja index 22db8d90..8aa8d6ba 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-delete-body-text.jinja @@ -1,4 +1,4 @@ -- Project: {{ object.project.name }} -- Task #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- Task #{{ snapshot.ref }}: {{ snapshot.subject }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/tasks/task-delete-subject.jinja b/taiga/projects/notifications/templates/emails/tasks/task-delete-subject.jinja index 00b8afc2..5a411013 100644 --- a/taiga/projects/notifications/templates/emails/tasks/task-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/tasks/task-delete-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Deleted the task #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Deleted the task #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-html.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-html.jinja index f73ad4e1..770ae1a0 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-html.jinja @@ -1,22 +1,24 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("userstory", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View US #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("userstory", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View US #{0}".format(snapshot.ref) %} {% block body %}
-

{{ object.project.name }}

-

Task #{{ object.ref }}: {{ object.subject }}

+

{{ project.name }}

+

Task #{{ snapshot.ref }}: {{ snapshot.subject }}

Deleted by {{ changer.get_full_name() }}

-

Project: {{ object.project.name }}

-

US #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

US #{{ snapshot.ref }}: {{ snapshot.subject }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ mdrender(object.project, comment)}}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ mdrender(project, entry.comment) }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + {% endfor %}
diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-text.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-text.jinja index e796e9bc..95195b79 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-change-body-text.jinja @@ -1,15 +1,17 @@ -{% set final_url = resolve_front_url("userstory", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View US #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("userstory", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View US #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- US #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- US #{{ snapshot.ref }}: {{ snapshot.subject }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% include "emails/includes/fields_diff-text.jinja" %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-text.jinja" %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-change-subject.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-change-subject.jinja index e1fe8bb4..5c66b14f 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-change-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Updated the US #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Updated the US #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-html.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-html.jinja index 8e530f34..922aa86f 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-html.jinja @@ -1,14 +1,14 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("userstory", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View US #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("userstory", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View US #{0}".format(snapshot.ref) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-text.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-text.jinja index 4caa83a4..850d1d3a 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-create-body-text.jinja @@ -1,8 +1,8 @@ -{% set final_url = resolve_front_url("userstory", object.project.slug, object.ref) %} -{% set final_url_name = "Taiga - View US #{0}".format(object.ref) %} +{% set final_url = resolve_front_url("userstory", project.slug, snapshot.ref) %} +{% set final_url_name = "Taiga - View US #{0}".format(snapshot.ref) %} -- Project: {{ object.project.name }} -- US #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- US #{{ snapshot.ref }}: {{ snapshot.subject }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-create-subject.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-create-subject.jinja index c17c460f..59f4b8db 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-create-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Created the US #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Created the US #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-html.jinja index 549d786d..75d3c14d 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-html.jinja @@ -4,8 +4,8 @@
-

Project: {{ object.project.name }}

-

US #{{ object.ref }}: {{ object.subject }}

+

Project: {{ project.name }}

+

US #{{ snapshot.ref }}: {{ snapshot.subject }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-text.jinja index 0dbb68b7..7ea708ce 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-body-text.jinja @@ -1,3 +1,3 @@ -- Project: {{ object.project.name }} -- US #{{ object.ref }}: {{ object.subject }} +- Project: {{ project.name }} +- US #{{ snapshot.ref }}: {{ snapshot.subject }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-subject.jinja b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-subject.jinja index 118117d7..1b315744 100644 --- a/taiga/projects/notifications/templates/emails/userstories/userstory-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/userstories/userstory-delete-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Deleted the US #{{ object.ref }} "{{ object.subject|safe }}" +[{{ project.name|safe }}] Deleted the US #{{ snapshot.ref }} "{{ snapshot.subject|safe }}" diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-html.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-html.jinja index 3bde4285..c7694c4a 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-html.jinja @@ -1,22 +1,24 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("wiki", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(object.slug) %} +{% set final_url = resolve_front_url("wiki", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(snapshot.slug) %} {% block body %}
-

{{ object.project.name }}

-

US #{{ object.ref }}: {{ object.subject }}

+

{{ project.name }}

+

US #{{ snapshot.ref }}: {{ snapshot.subject }}

Deleted by {{ changer.get_full_name() }}

-

Project: {{ object.project.name }}

-

Wiki Page: {{ object.slug }}

+

Project: {{ project.name }}

+

Wiki Page: {{ snapshot.slug }}

Updated by {{ changer.get_full_name() }}.

- {% if comment %} -

Comment {{ mdrender(object.project, comment) }}

- {% endif %} - {% if changed_fields %} -

Updated fields:

- {% include "emails/includes/fields_diff-html.jinja" %} - {% endif %} + {% for entry in history_entries%} + {% if entry.comment %} +

Comment {{ mdrender(project, entry.comment) }}

+ {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-html.jinja" %} + {% endif %} + {% endfor %}
diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-text.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-text.jinja index b358d18f..50bc8d74 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-body-text.jinja @@ -1,15 +1,17 @@ -{% set final_url = resolve_front_url("wiki", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(object.slug) %} +{% set final_url = resolve_front_url("wiki", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(snapshot.slug) %} -- Project: {{ object.project.name }} -- Wiki Page: {{ object.slug }} +- Project: {{ project.name }} +- Wiki Page: {{ snapshot.slug }} - Updated by {{ changer.get_full_name() }} -{% if comment %} -Comment: {{ comment|linebreaksbr }} -{% endif %} -{% if changed_fields %} -- Updated fields: - {% include "emails/includes/fields_diff-text.jinja" %} -{% endif %} +{% for entry in history_entries%} + {% if entry.comment %} + Comment: {{ entry.comment|linebreaksbr }} + {% endif %} + {% set changed_fields = entry.values_diff %} + {% if changed_fields %} + {% include "emails/includes/fields_diff-text.jinja" %} + {% endif %} +{% endfor %} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-subject.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-subject.jinja index 18413c2d..024d566e 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-change-subject.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-change-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Updated the Wiki Page "{{ object.slug }}" +[{{ project.name|safe }}] Updated the Wiki Page "{{ snapshot.slug }}" diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-html.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-html.jinja index 5eaf9f83..6112a0c5 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-html.jinja @@ -1,14 +1,14 @@ {% extends "emails/base.jinja" %} -{% set final_url = resolve_front_url("wiki", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(object.slug) %} +{% set final_url = resolve_front_url("wiki", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(snapshot.slug) %} {% block body %} diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-text.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-text.jinja index b41f4b8c..70bb34e9 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-body-text.jinja @@ -1,8 +1,8 @@ -{% set final_url = resolve_front_url("wiki", object.project.slug, object.slug) %} -{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(object.slug) %} +{% set final_url = resolve_front_url("wiki", project.slug, snapshot.slug) %} +{% set final_url_name = "Taiga - View Wiki Page '{0}'".format(snapshot.slug) %} -- Project: {{ object.project.name }} -- Wiki Page: {{ object.slug }} +- Project: {{ project.name }} +- Wiki Page: {{ snapshot.slug }} - Created by {{ changer.get_full_name() }} ** More info at {{ final_url_name }} ({{ final_url }}) ** diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-subject.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-subject.jinja index a32efed4..af4ca48d 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-create-subject.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-create-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Created the Wiki Page "{{ object.slug }}" +[{{ project.name|safe }}] Created the Wiki Page "{{ snapshot.slug }}" diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-html.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-html.jinja index 6f9bc2ba..4e98c508 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-html.jinja @@ -4,8 +4,8 @@
-

Project: {{ object.project.name }}

-

Wiki Page: {{ object.slug }}

+

Project: {{ project.name }}

+

Wiki Page: {{ snapshot.slug }}

Created by {{ changer.get_full_name() }}.

diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-text.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-text.jinja index e69b4559..d896f42f 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-text.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-body-text.jinja @@ -1,3 +1,3 @@ -- Project: {{ object.project.name }} -- Wiki Page: {{ object.slug }} +- Project: {{ project.name }} +- Wiki Page: {{ snapshot.slug }} - Deleted by {{ changer.get_full_name() }} diff --git a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-subject.jinja b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-subject.jinja index 7fd60924..a496edc2 100644 --- a/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-subject.jinja +++ b/taiga/projects/notifications/templates/emails/wiki/wikipage-delete-subject.jinja @@ -1 +1 @@ -[{{ object.project.name|safe }}] Deleted the Wiki Page "{{ object.slug }}" +[{{ project.name|safe }}] Deleted the Wiki Page "{{ snapshot.slug }}" From 6e313abfbd45d69dec21f44551a3d8b2dfdb5b82 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:03:20 +0100 Subject: [PATCH 04/10] Adding migrations --- .../0002_historychangenotification.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 taiga/projects/notifications/migrations/0002_historychangenotification.py diff --git a/taiga/projects/notifications/migrations/0002_historychangenotification.py b/taiga/projects/notifications/migrations/0002_historychangenotification.py new file mode 100644 index 00000000..a8b92490 --- /dev/null +++ b/taiga/projects/notifications/migrations/0002_historychangenotification.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('projects', '0005_membership_invitation_extra_text'), + ('history', '0004_historyentry_is_hidden'), + ('notifications', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='HistoryChangeNotification', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True, verbose_name='ID', auto_created=True)), + ('key', models.CharField(max_length=255, editable=False)), + ('created_datetime', models.DateTimeField(verbose_name='created date time', auto_now_add=True)), + ('updated_datetime', models.DateTimeField(verbose_name='updated date time', auto_now_add=True)), + ('history_type', models.SmallIntegerField(choices=[(1, 'Change'), (2, 'Create'), (3, 'Delete')])), + ('history_entries', models.ManyToManyField(blank=True, null=True, to='history.HistoryEntry', verbose_name='history entries', related_name='+')), + ('notify_users', models.ManyToManyField(blank=True, null=True, to=settings.AUTH_USER_MODEL, verbose_name='notify users', related_name='+')), + ('owner', models.ForeignKey(related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='owner')), + ('project', models.ForeignKey(related_name='+', to='projects.Project', verbose_name='project')), + ], + options={ + }, + bases=(models.Model,), + ), + ] From 38fc63425a75badab8e58582383818ca0f475f02 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:03:33 +0100 Subject: [PATCH 05/10] Fixing tests --- tests/integration/test_notifications.py | 80 ++++++++++++++----------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/tests/integration/test_notifications.py b/tests/integration/test_notifications.py index 411f67bd..f63ec656 100644 --- a/tests/integration/test_notifications.py +++ b/tests/integration/test_notifications.py @@ -22,15 +22,17 @@ from unittest.mock import MagicMock, patch from django.core.urlresolvers import reverse from django.apps import apps from .. import factories as f +from .. utils import set_settings from taiga.projects.notifications import services +from taiga.projects.notifications import models from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.history.choices import HistoryType +from taiga.projects.history.services import take_snapshot from taiga.projects.issues.serializers import IssueSerializer from taiga.projects.userstories.serializers import UserStorySerializer from taiga.projects.tasks.serializers import TaskSerializer - pytestmark = pytest.mark.django_db @@ -118,7 +120,7 @@ def test_users_to_notify(): # Test basic description modifications issue.description = "test1" issue.save() - users = services.get_users_to_notify(issue, history=history) + users = services.get_users_to_notify(issue) assert len(users) == 1 assert tuple(users)[0] == issue.get_owner() @@ -126,13 +128,13 @@ def test_users_to_notify(): policy1.notify_level = NotifyLevel.watch policy1.save() - users = services.get_users_to_notify(issue, history=history) + users = services.get_users_to_notify(issue) assert len(users) == 2 assert users == {member1.user, issue.get_owner()} # Test with watchers issue.watchers.add(member3.user) - users = services.get_users_to_notify(issue, history=history) + users = services.get_users_to_notify(issue) assert len(users) == 3 assert users == {member1.user, member3.user, issue.get_owner()} @@ -141,90 +143,87 @@ def test_users_to_notify(): policy3.save() issue.watchers.add(member3.user) - users = services.get_users_to_notify(issue, history=history) + users = services.get_users_to_notify(issue) assert len(users) == 2 assert users == {member1.user, issue.get_owner()} - +@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=0) def test_send_notifications_using_services_method(mail): project = f.ProjectFactory.create() member1 = f.MembershipFactory.create(project=project) member2 = f.MembershipFactory.create(project=project) history_change = MagicMock() - history_change.owner = member1.user + history_change.user = {"pk": member1.user.pk} history_change.comment = "" history_change.type = HistoryType.change history_create = MagicMock() - history_create.owner = member1.user + history_create.user = {"pk": member1.user.pk} history_create.comment = "" history_create.type = HistoryType.create history_delete = MagicMock() - history_delete.owner = member1.user + history_delete.user = {"pk": member1.user.pk} history_delete.comment = "" history_delete.type = HistoryType.delete # Issues issue = f.IssueFactory.create(project=project) + take_snapshot(issue) services.send_notifications(issue, - history=history_create, - users={member1.user, member2.user}) + history=history_create) services.send_notifications(issue, - history=history_change, - users={member1.user, member2.user}) + history=history_change) services.send_notifications(issue, - history=history_delete, - users={member1.user, member2.user}) + history=history_delete) + # Userstories us = f.UserStoryFactory.create() + take_snapshot(us) services.send_notifications(us, - history=history_create, - users={member1.user, member2.user}) + history=history_create) services.send_notifications(us, - history=history_change, - users={member1.user, member2.user}) + history=history_change) services.send_notifications(us, - history=history_delete, - users={member1.user, member2.user}) + history=history_delete) + # Tasks task = f.TaskFactory.create() + take_snapshot(task) services.send_notifications(task, - history=history_create, - users={member1.user, member2.user}) + history=history_create) services.send_notifications(task, - history=history_change, - users={member1.user, member2.user}) + history=history_change) services.send_notifications(task, - history=history_delete, - users={member1.user, member2.user}) + history=history_delete) # Wiki pages wiki = f.WikiPageFactory.create() + take_snapshot(wiki) services.send_notifications(wiki, - history=history_create, - users={member1.user, member2.user}) + history=history_create) services.send_notifications(wiki, - history=history_change, - users={member1.user, member2.user}) + history=history_change) services.send_notifications(wiki, - history=history_delete, - users={member1.user, member2.user}) - - assert len(mail.outbox) == 24 + history=history_delete) + assert models.HistoryChangeNotification.objects.count() == 12 + assert len(mail.outbox) == 0 + services.process_sync_notifications() + assert len(mail.outbox) == 12 +@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=0) def test_resource_notification_test(client, mail): user1 = f.UserFactory.create() user2 = f.UserFactory.create() @@ -242,13 +241,22 @@ def test_resource_notification_test(client, mail): with patch(mock_path) as m: data = {"subject": "Fooooo", "version": issue.version} response = client.patch(url, json.dumps(data), content_type="application/json") - assert len(mail.outbox) == 1 assert response.status_code == 200 + assert len(mail.outbox) == 0 + assert models.HistoryChangeNotification.objects.count() == 1 + services.process_sync_notifications() + assert len(mail.outbox) == 1 + assert models.HistoryChangeNotification.objects.count() == 0 + with patch(mock_path) as m: response = client.delete(url) assert response.status_code == 204 + assert len(mail.outbox) == 1 + assert models.HistoryChangeNotification.objects.count() == 1 + services.process_sync_notifications() assert len(mail.outbox) == 2 + assert models.HistoryChangeNotification.objects.count() == 0 def test_watchers_assignation_for_issue(client): From 864734c97e3dd9b3d7a5264eb1c67cb5d2b7b45b Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:06:01 +0100 Subject: [PATCH 06/10] Adding managemente command for sending pending notifications --- .../management/commands/__init__.py | 0 .../management/commands/send_notifications.py | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 taiga/projects/notifications/management/commands/__init__.py create mode 100644 taiga/projects/notifications/management/commands/send_notifications.py diff --git a/taiga/projects/notifications/management/commands/__init__.py b/taiga/projects/notifications/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/taiga/projects/notifications/management/commands/send_notifications.py b/taiga/projects/notifications/management/commands/send_notifications.py new file mode 100644 index 00000000..74c9bf31 --- /dev/null +++ b/taiga/projects/notifications/management/commands/send_notifications.py @@ -0,0 +1,27 @@ +# Copyright (C) 2014 Andrey Antukh +# Copyright (C) 2014 Jesús Espino +# Copyright (C) 2014 David Barragán +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from django.core.management.base import BaseCommand + +from taiga.projects.notifications.models import HistoryChangeNotification +from taiga.projects.notifications.services import send_sync_notifications + +class Command(BaseCommand): + + def handle(self, *args, **options): + for change_notification in HistoryChangeNotification.objects.all(): + send_sync_notifications(change_notification.pk) From 08b8d478e1c8ce071ec695572049ff73a9755822 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 18:26:30 +0100 Subject: [PATCH 07/10] Making notifications work synchronously by default --- settings/common.py | 5 ++++- taiga/projects/notifications/services.py | 3 +++ tests/integration/test_notifications.py | 10 ++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/settings/common.py b/settings/common.py index 3aef9bdf..fe66d2ba 100644 --- a/settings/common.py +++ b/settings/common.py @@ -332,7 +332,10 @@ TAGS_PREDEFINED_COLORS = ["#fce94f", "#edd400", "#c4a000", "#8ae234", FEEDBACK_ENABLED = True FEEDBACK_EMAIL = "support@taiga.io" -CHANGE_NOTIFICATIONS_MIN_INTERVAL = 30 #seconds +# 0 notifications will work in a synchronous way +# >0 an external process will check the pending notifications and will send them +# collapsed during that interval +CHANGE_NOTIFICATIONS_MIN_INTERVAL = 0 #seconds # NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE TEST_RUNNER="django.test.runner.DiscoverRunner" diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index 746beace..eac805e2 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -205,6 +205,9 @@ def send_notifications(obj, *, history): for notify_user in notify_users: notification.notify_users.add(notify_user) + # 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) @transaction.atomic def send_sync_notifications(notification_id): diff --git a/tests/integration/test_notifications.py b/tests/integration/test_notifications.py index f63ec656..da0e6bd4 100644 --- a/tests/integration/test_notifications.py +++ b/tests/integration/test_notifications.py @@ -17,6 +17,7 @@ import json import pytest +import time from unittest.mock import MagicMock, patch from django.core.urlresolvers import reverse @@ -147,7 +148,7 @@ def test_users_to_notify(): assert len(users) == 2 assert users == {member1.user, issue.get_owner()} -@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=0) +@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=1) def test_send_notifications_using_services_method(mail): project = f.ProjectFactory.create() member1 = f.MembershipFactory.create(project=project) @@ -219,11 +220,11 @@ def test_send_notifications_using_services_method(mail): assert models.HistoryChangeNotification.objects.count() == 12 assert len(mail.outbox) == 0 + time.sleep(1) services.process_sync_notifications() - assert len(mail.outbox) == 12 -@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=0) +@set_settings(CHANGE_NOTIFICATIONS_MIN_INTERVAL=1) def test_resource_notification_test(client, mail): user1 = f.UserFactory.create() user2 = f.UserFactory.create() @@ -242,9 +243,9 @@ def test_resource_notification_test(client, mail): data = {"subject": "Fooooo", "version": issue.version} response = client.patch(url, json.dumps(data), content_type="application/json") assert response.status_code == 200 - assert len(mail.outbox) == 0 assert models.HistoryChangeNotification.objects.count() == 1 + time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 1 assert models.HistoryChangeNotification.objects.count() == 0 @@ -254,6 +255,7 @@ def test_resource_notification_test(client, mail): assert response.status_code == 204 assert len(mail.outbox) == 1 assert models.HistoryChangeNotification.objects.count() == 1 + time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 2 assert models.HistoryChangeNotification.objects.count() == 0 From fac330246b1ae6464b6a927f6efe6a73c442d98a Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 28 Oct 2014 22:07:17 +0100 Subject: [PATCH 08/10] Removing unnecesary print --- taiga/projects/notifications/services.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index eac805e2..ba08918e 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -207,7 +207,7 @@ def send_notifications(obj, *, history): # 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) + send_sync_notifications(notification.id) @transaction.atomic def send_sync_notifications(notification_id): @@ -222,7 +222,6 @@ def send_sync_notifications(notification_id): now = timezone.now() time_diff = now - notification.updated_datetime if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL: - print(time_diff.seconds) return history_entries = tuple(notification.history_entries.all().order_by("created_at")) From 50ceecb11545e787a777b87ab7642a320743e7a7 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 29 Oct 2014 08:49:29 +0100 Subject: [PATCH 09/10] Fixing issue change body email notification template --- .../templates/emails/issues/issue-change-body-html.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja b/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja index 0f517727..301f351b 100644 --- a/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja +++ b/taiga/projects/notifications/templates/emails/issues/issue-change-body-html.jinja @@ -18,8 +18,8 @@ {% if changed_fields %} {% include "emails/includes/fields_diff-html.jinja" %} {% endif %} - {% endfor %} +
-

{{ object.project.name }}

-

Wiki Page: {{ object.slug }}

+

{{ project.name }}

+

Wiki Page: {{ snapshot.slug }}

Deleted by {{ changer.get_full_name() }}

{% endblock %} From 94a4708df7db63bc8dc454744739cee2d371714b Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 29 Oct 2014 09:12:04 +0100 Subject: [PATCH 10/10] Using iterqueryset in management command --- .../notifications/management/commands/send_notifications.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/taiga/projects/notifications/management/commands/send_notifications.py b/taiga/projects/notifications/management/commands/send_notifications.py index 74c9bf31..4f2e4643 100644 --- a/taiga/projects/notifications/management/commands/send_notifications.py +++ b/taiga/projects/notifications/management/commands/send_notifications.py @@ -17,11 +17,13 @@ from django.core.management.base import BaseCommand +from taiga.base.utils.iterators import iter_queryset from taiga.projects.notifications.models import HistoryChangeNotification from taiga.projects.notifications.services import send_sync_notifications class Command(BaseCommand): def handle(self, *args, **options): - for change_notification in HistoryChangeNotification.objects.all(): + qs = HistoryChangeNotification.objects.all() + for change_notification in iter_queryset(qs, itersize=100): send_sync_notifications(change_notification.pk)