From db34ad32c98faf1d15e6c88eac37c47cf55e749d Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 12 Sep 2016 14:10:50 +0200 Subject: [PATCH] Including epic in timelines --- taiga/projects/epics/api.py | 11 +++++++---- taiga/projects/epics/models.py | 10 +++++++++- taiga/projects/epics/services.py | 2 +- taiga/projects/history/freeze_impl.py | 15 ++++++++++++++- taiga/projects/history/services.py | 4 ++++ taiga/projects/mixins/serializers.py | 3 ++- taiga/projects/notifications/services.py | 1 + taiga/timeline/service.py | 17 +++++++++++++++-- taiga/timeline/timeline_implementations.py | 16 +++++++++++++++- 9 files changed, 68 insertions(+), 11 deletions(-) diff --git a/taiga/projects/epics/api.py b/taiga/projects/epics/api.py index 81dd242e..fce31802 100644 --- a/taiga/projects/epics/api.py +++ b/taiga/projects/epics/api.py @@ -22,7 +22,7 @@ from django.utils.translation import ugettext as _ from taiga.base.api.utils import get_object_or_404 from taiga.base import filters, response from taiga.base import exceptions as exc -from taiga.base.decorators import list_route, detail_route +from taiga.base.decorators import list_route from taiga.base.api import ModelCrudViewSet, ModelListViewSet from taiga.base.api.mixins import BlockedByProjectMixin from taiga.base.api.viewsets import NestedViewSetMixin @@ -33,7 +33,6 @@ from taiga.projects.models import Project, EpicStatus from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.occ import OCCResourceMixin from taiga.projects.tagging.api import TaggedResourceMixin -from taiga.projects.userstories.models import UserStory from taiga.projects.votes.mixins.viewsets import VotedResourceMixin, VotersViewSetMixin from . import models @@ -226,7 +225,8 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, return response.Ok(epics_serialized.data) -class EpicRelatedUserStoryViewSet(NestedViewSetMixin, BlockedByProjectMixin, ModelCrudViewSet): +class EpicRelatedUserStoryViewSet(NestedViewSetMixin, HistoryResourceMixin, + BlockedByProjectMixin, ModelCrudViewSet): queryset = models.RelatedUserStory.objects.all() serializer_class = serializers.EpicRelatedUserStorySerializer validator_class = validators.EpicRelatedUserStoryValidator @@ -288,13 +288,16 @@ class EpicRelatedUserStoryViewSet(NestedViewSetMixin, BlockedByProjectMixin, Mod if project.blocked_code is not None: raise exc.Blocked(_("Blocked element")) - services.create_related_userstories_in_bulk( + related_userstories = services.create_related_userstories_in_bulk( data["bulk_userstories"], epic, project=project, owner=request.user ) + for related_userstory in related_userstories: + self.persist_history_snapshot(obj=related_userstory) + related_uss_serialized = self.get_serializer_class()(epic.relateduserstory_set.all(), many=True) return response.Ok(related_uss_serialized.data) diff --git a/taiga/projects/epics/models.py b/taiga/projects/epics/models.py index 64bdbb84..f41cec30 100644 --- a/taiga/projects/epics/models.py +++ b/taiga/projects/epics/models.py @@ -92,7 +92,7 @@ class Epic(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.M super().save(*args, **kwargs) -class RelatedUserStory(models.Model): +class RelatedUserStory(WatchedModelMixin, models.Model): user_story = models.ForeignKey("userstories.UserStory", on_delete=models.CASCADE) epic = models.ForeignKey("epics.Epic", on_delete=models.CASCADE) @@ -111,3 +111,11 @@ class RelatedUserStory(models.Model): @property def project(self): return self.epic.project + + @property + def owner_id(self): + return self.epic.owner_id + + @property + def assigned_to_id(self): + return self.epic.assigned_to_id diff --git a/taiga/projects/epics/services.py b/taiga/projects/epics/services.py index bf0edff5..610bfcfb 100644 --- a/taiga/projects/epics/services.py +++ b/taiga/projects/epics/services.py @@ -124,7 +124,7 @@ def create_related_userstories_in_bulk(bulk_data, epic, **additional_fields): finally: connect_userstories_signals() - return userstories + return related_userstories def update_epic_related_userstories_order_in_bulk(bulk_data: list, epic: object): diff --git a/taiga/projects/history/freeze_impl.py b/taiga/projects/history/freeze_impl.py index 489f2c79..6804c249 100644 --- a/taiga/projects/history/freeze_impl.py +++ b/taiga/projects/history/freeze_impl.py @@ -112,8 +112,11 @@ def epic_values(diff): if "status" in diff: values["status"] = _get_us_status_values(diff["status"]) - # TODO EPICS: What happen with usr stories? + return values + +def epic_related_userstory_values(diff): + values = _common_users_values(diff) return values @@ -317,6 +320,16 @@ def epic_freezer(epic) -> dict: return snapshot +def epic_related_userstory_freezer(related_us) -> dict: + snapshot = { + "user_story": related_us.user_story.id, + "epic": related_us.epic.id, + "order": related_us.order + } + + return snapshot + + def userstory_freezer(us) -> dict: rp_cls = apps.get_model("userstories", "RolePoints") rpqsd = rp_cls.objects.filter(user_story=us) diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py index 54dd78fc..019cf258 100644 --- a/taiga/projects/history/services.py +++ b/taiga/projects/history/services.py @@ -51,6 +51,7 @@ from .models import HistoryType from .freeze_impl import project_freezer from .freeze_impl import milestone_freezer from .freeze_impl import epic_freezer +from .freeze_impl import epic_related_userstory_freezer from .freeze_impl import userstory_freezer from .freeze_impl import issue_freezer from .freeze_impl import task_freezer @@ -60,6 +61,7 @@ from .freeze_impl import wikipage_freezer from .freeze_impl import project_values from .freeze_impl import milestone_values from .freeze_impl import epic_values +from .freeze_impl import epic_related_userstory_values from .freeze_impl import userstory_values from .freeze_impl import issue_values from .freeze_impl import task_values @@ -397,6 +399,7 @@ def prefetch_owners_in_history_queryset(qs): register_freeze_implementation("projects.project", project_freezer) register_freeze_implementation("milestones.milestone", milestone_freezer,) register_freeze_implementation("epics.epic", epic_freezer) +register_freeze_implementation("epics.relateduserstory", epic_related_userstory_freezer) register_freeze_implementation("userstories.userstory", userstory_freezer) register_freeze_implementation("issues.issue", issue_freezer) register_freeze_implementation("tasks.task", task_freezer) @@ -405,6 +408,7 @@ register_freeze_implementation("wiki.wikipage", wikipage_freezer) register_values_implementation("projects.project", project_values) register_values_implementation("milestones.milestone", milestone_values) register_values_implementation("epics.epic", epic_values) +register_values_implementation("epics.relateduserstory", epic_related_userstory_values) register_values_implementation("userstories.userstory", userstory_values) register_values_implementation("issues.issue", issue_values) register_values_implementation("tasks.task", task_values) diff --git a/taiga/projects/mixins/serializers.py b/taiga/projects/mixins/serializers.py index 67949877..c8a70932 100644 --- a/taiga/projects/mixins/serializers.py +++ b/taiga/projects/mixins/serializers.py @@ -98,7 +98,8 @@ class ProjectExtraInfoSerializerMixin(serializers.LightSerializer): serialized_project = { "name": obj.project.name, "slug": obj.project.slug, - "logo_small_url": services.get_logo_small_thumbnail_url(obj.project) + "logo_small_url": services.get_logo_small_thumbnail_url(obj.project), + "id": obj.project_id } self._serialized_project[obj.project_id] = serialized_project diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index 4c7012d1..e998d068 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -336,6 +336,7 @@ def get_related_people(obj): related_people = related_people.exclude(is_active=False) related_people = related_people.exclude(is_system=True) related_people = related_people.distinct() + return related_people diff --git a/taiga/timeline/service.py b/taiga/timeline/service.py index 94d37c80..03ca3e96 100644 --- a/taiga/timeline/service.py +++ b/taiga/timeline/service.py @@ -94,6 +94,7 @@ def _push_to_timeline(objects, instance: object, event_type: str, created_dateti @app.task def push_to_timelines(project_id, user_id, obj_app_label, obj_model_name, obj_id, event_type, created_datetime, extra_data={}): + ObjModel = apps.get_model(obj_app_label, obj_model_name) try: obj = ObjModel.objects.get(id=obj_id) @@ -266,13 +267,25 @@ def extract_epic_info(instance): } -def extract_userstory_info(instance): - return { +def extract_userstory_info(instance, include_project=False): + userstory_info = { "id": instance.pk, "ref": instance.ref, "subject": instance.subject, } + if include_project: + userstory_info["project"] = extract_project_info(instance.project) + + return userstory_info + + +def extract_related_userstory_info(instance): + return { + "id": instance.pk, + "subject": instance.user_story.subject + } + def extract_issue_info(instance): return { diff --git a/taiga/timeline/timeline_implementations.py b/taiga/timeline/timeline_implementations.py index 9b97fa06..1d480e82 100644 --- a/taiga/timeline/timeline_implementations.py +++ b/taiga/timeline/timeline_implementations.py @@ -47,7 +47,7 @@ def milestone_timeline(instance, extra_data={}): @register_timeline_implementation("epics.epic", "change") @register_timeline_implementation("epics.epic", "delete") def epic_timeline(instance, extra_data={}): - result ={ + result = { "epic": service.extract_epic_info(instance), "project": service.extract_project_info(instance.project), } @@ -55,6 +55,20 @@ def epic_timeline(instance, extra_data={}): return result +@register_timeline_implementation("epics.relateduserstory", "create") +@register_timeline_implementation("epics.relateduserstory", "change") +@register_timeline_implementation("epics.relateduserstory", "delete") +def epic_related_userstory_timeline(instance, extra_data={}): + result = { + "relateduserstory": service.extract_related_userstory_info(instance), + "epic": service.extract_epic_info(instance.epic), + "userstory": service.extract_userstory_info(instance.user_story, include_project=True), + "project": service.extract_project_info(instance.project), + } + result.update(extra_data) + return result + + @register_timeline_implementation("userstories.userstory", "create") @register_timeline_implementation("userstories.userstory", "change") @register_timeline_implementation("userstories.userstory", "delete")