From a4256c3f093879e318c29a040fa435e6a1588d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Hermida?= Date: Fri, 28 Dec 2018 14:09:39 +0100 Subject: [PATCH] Add issue milestones signals --- taiga/projects/issues/apps.py | 21 ++++++++++ taiga/projects/issues/signals.py | 58 +++++++++++++++++++++++++++ taiga/projects/milestones/services.py | 3 +- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/taiga/projects/issues/apps.py b/taiga/projects/issues/apps.py index 81a5ddce..331d6916 100644 --- a/taiga/projects/issues/apps.py +++ b/taiga/projects/issues/apps.py @@ -25,6 +25,11 @@ def connect_issues_signals(): from taiga.projects.tagging import signals as tagging_handlers from . import signals as handlers + # Cached prev object version + signals.pre_save.connect(handlers.cached_prev_issue, + sender=apps.get_model("issues", "Issue"), + dispatch_uid="cached_prev_issue") + # Finished date signals.pre_save.connect(handlers.set_finished_date_when_edit_issue, sender=apps.get_model("issues", "Issue"), @@ -35,6 +40,14 @@ def connect_issues_signals(): sender=apps.get_model("issues", "Issue"), dispatch_uid="tags_normalization_issue") + # Open/Close US and Milestone + signals.post_save.connect(handlers.try_to_close_or_open_milestone_when_create_or_edit_issue, + sender=apps.get_model("issues", "Issue"), + dispatch_uid="try_to_close_or_open_milestone_when_create_or_edit_issue") + signals.post_delete.connect(handlers.try_to_close_milestone_when_delete_issue, + sender=apps.get_model("issues", "Issue"), + dispatch_uid="try_to_close_milestone_when_delete_issue") + def connect_issues_custom_attributes_signals(): from taiga.projects.custom_attributes import signals as custom_attributes_handlers @@ -50,11 +63,19 @@ def connect_all_issues_signals(): def disconnect_issues_signals(): + signals.pre_save.disconnect(sender=apps.get_model("issues", "Issue"), + dispatch_uid="cached_prev_issue") + signals.pre_save.disconnect(sender=apps.get_model("issues", "Issue"), dispatch_uid="set_finished_date_when_edit_issue") signals.pre_save.disconnect(sender=apps.get_model("issues", "Issue"), dispatch_uid="tags_normalization_issue") + signals.post_save.disconnect(sender=apps.get_model("issues", "Issue"), + dispatch_uid="try_to_close_or_open_milestone_when_create_or_edit_issue") + signals.post_delete.disconnect(sender=apps.get_model("issues", "Issue"), + dispatch_uid="try_to_close_milestone_when_delete_issue") + def disconnect_issues_custom_attributes_signals(): signals.post_save.disconnect(sender=apps.get_model("issues", "Issue"), diff --git a/taiga/projects/issues/signals.py b/taiga/projects/issues/signals.py index ce2b6cab..04b71bb6 100644 --- a/taiga/projects/issues/signals.py +++ b/taiga/projects/issues/signals.py @@ -16,9 +16,22 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from contextlib import suppress +from django.core.exceptions import ObjectDoesNotExist from django.utils import timezone +#################################### +# Signals for cached prev task +#################################### + +# Define the previous version of the task for use it on the post_save handler +def cached_prev_issue(sender, instance, **kwargs): + instance.prev = None + if instance.id: + instance.prev = sender.objects.get(id=instance.id) + + #################################### # Signals for set finished date #################################### @@ -30,3 +43,48 @@ def set_finished_date_when_edit_issue(sender, instance, **kwargs): instance.finished_date = timezone.now() elif not instance.status.is_closed and instance.finished_date: instance.finished_date = None + + +def try_to_close_or_open_milestone_when_create_or_edit_issue(sender, instance, created, **kwargs): + if instance._importing: + return + + _try_to_close_or_open_milestone_when_create_or_edit_issue(instance) + + +def try_to_close_milestone_when_delete_issue(sender, instance, **kwargs): + if instance._importing: + return + + _try_to_close_milestone_when_delete_issue(instance) + + +# Milestone +def _try_to_close_or_open_milestone_when_create_or_edit_issue(instance): + if instance._importing: + return + + from taiga.projects.milestones import services as milestone_service + + if instance.milestone_id: + if milestone_service.calculate_milestone_is_closed(instance.milestone): + milestone_service.close_milestone(instance.milestone) + else: + milestone_service.open_milestone(instance.milestone) + + if instance.prev and instance.prev.milestone_id and instance.prev.milestone_id != instance.milestone_id: + if milestone_service.calculate_milestone_is_closed(instance.prev.milestone): + milestone_service.close_milestone(instance.prev.milestone) + else: + milestone_service.open_milestone(instance.prev.milestone) + + +def _try_to_close_milestone_when_delete_issue(instance): + if instance._importing: + return + + from taiga.projects.milestones import services as milestone_service + + with suppress(ObjectDoesNotExist): + if instance.milestone_id and milestone_service.calculate_milestone_is_closed(instance.milestone): + milestone_service.close_milestone(instance.milestone) diff --git a/taiga/projects/milestones/services.py b/taiga/projects/milestones/services.py index 041fa0a0..92db010f 100644 --- a/taiga/projects/milestones/services.py +++ b/taiga/projects/milestones/services.py @@ -30,7 +30,8 @@ from . import models def calculate_milestone_is_closed(milestone): return (milestone.user_stories.all().count() > 0 and all([task.status is not None and task.status.is_closed for task in milestone.tasks.all()]) and - all([user_story.is_closed for user_story in milestone.user_stories.all()])) + all([user_story.is_closed for user_story in milestone.user_stories.all()]) or + all([issue.is_closed for issue in milestone.issues.all()])) def close_milestone(milestone):