Including epic in timelines

remotes/origin/issue/4795/notification_even_they_are_disabled
Alejandro Alonso 2016-09-12 14:10:50 +02:00
parent 35b799e89d
commit db34ad32c9
9 changed files with 68 additions and 11 deletions

View File

@ -22,7 +22,7 @@ from django.utils.translation import ugettext as _
from taiga.base.api.utils import get_object_or_404 from taiga.base.api.utils import get_object_or_404
from taiga.base import filters, response from taiga.base import filters, response
from taiga.base import exceptions as exc 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 import ModelCrudViewSet, ModelListViewSet
from taiga.base.api.mixins import BlockedByProjectMixin from taiga.base.api.mixins import BlockedByProjectMixin
from taiga.base.api.viewsets import NestedViewSetMixin 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.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin
from taiga.projects.occ import OCCResourceMixin from taiga.projects.occ import OCCResourceMixin
from taiga.projects.tagging.api import TaggedResourceMixin from taiga.projects.tagging.api import TaggedResourceMixin
from taiga.projects.userstories.models import UserStory
from taiga.projects.votes.mixins.viewsets import VotedResourceMixin, VotersViewSetMixin from taiga.projects.votes.mixins.viewsets import VotedResourceMixin, VotersViewSetMixin
from . import models from . import models
@ -226,7 +225,8 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
return response.Ok(epics_serialized.data) return response.Ok(epics_serialized.data)
class EpicRelatedUserStoryViewSet(NestedViewSetMixin, BlockedByProjectMixin, ModelCrudViewSet): class EpicRelatedUserStoryViewSet(NestedViewSetMixin, HistoryResourceMixin,
BlockedByProjectMixin, ModelCrudViewSet):
queryset = models.RelatedUserStory.objects.all() queryset = models.RelatedUserStory.objects.all()
serializer_class = serializers.EpicRelatedUserStorySerializer serializer_class = serializers.EpicRelatedUserStorySerializer
validator_class = validators.EpicRelatedUserStoryValidator validator_class = validators.EpicRelatedUserStoryValidator
@ -288,13 +288,16 @@ class EpicRelatedUserStoryViewSet(NestedViewSetMixin, BlockedByProjectMixin, Mod
if project.blocked_code is not None: if project.blocked_code is not None:
raise exc.Blocked(_("Blocked element")) raise exc.Blocked(_("Blocked element"))
services.create_related_userstories_in_bulk( related_userstories = services.create_related_userstories_in_bulk(
data["bulk_userstories"], data["bulk_userstories"],
epic, epic,
project=project, project=project,
owner=request.user 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) related_uss_serialized = self.get_serializer_class()(epic.relateduserstory_set.all(), many=True)
return response.Ok(related_uss_serialized.data) return response.Ok(related_uss_serialized.data)

View File

@ -92,7 +92,7 @@ class Epic(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.M
super().save(*args, **kwargs) super().save(*args, **kwargs)
class RelatedUserStory(models.Model): class RelatedUserStory(WatchedModelMixin, models.Model):
user_story = models.ForeignKey("userstories.UserStory", on_delete=models.CASCADE) user_story = models.ForeignKey("userstories.UserStory", on_delete=models.CASCADE)
epic = models.ForeignKey("epics.Epic", on_delete=models.CASCADE) epic = models.ForeignKey("epics.Epic", on_delete=models.CASCADE)
@ -111,3 +111,11 @@ class RelatedUserStory(models.Model):
@property @property
def project(self): def project(self):
return self.epic.project 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

View File

@ -124,7 +124,7 @@ def create_related_userstories_in_bulk(bulk_data, epic, **additional_fields):
finally: finally:
connect_userstories_signals() connect_userstories_signals()
return userstories return related_userstories
def update_epic_related_userstories_order_in_bulk(bulk_data: list, epic: object): def update_epic_related_userstories_order_in_bulk(bulk_data: list, epic: object):

View File

@ -112,8 +112,11 @@ def epic_values(diff):
if "status" in diff: if "status" in diff:
values["status"] = _get_us_status_values(diff["status"]) 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 return values
@ -317,6 +320,16 @@ def epic_freezer(epic) -> dict:
return snapshot 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: def userstory_freezer(us) -> dict:
rp_cls = apps.get_model("userstories", "RolePoints") rp_cls = apps.get_model("userstories", "RolePoints")
rpqsd = rp_cls.objects.filter(user_story=us) rpqsd = rp_cls.objects.filter(user_story=us)

View File

@ -51,6 +51,7 @@ from .models import HistoryType
from .freeze_impl import project_freezer from .freeze_impl import project_freezer
from .freeze_impl import milestone_freezer from .freeze_impl import milestone_freezer
from .freeze_impl import epic_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 userstory_freezer
from .freeze_impl import issue_freezer from .freeze_impl import issue_freezer
from .freeze_impl import task_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 project_values
from .freeze_impl import milestone_values from .freeze_impl import milestone_values
from .freeze_impl import epic_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 userstory_values
from .freeze_impl import issue_values from .freeze_impl import issue_values
from .freeze_impl import task_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("projects.project", project_freezer)
register_freeze_implementation("milestones.milestone", milestone_freezer,) register_freeze_implementation("milestones.milestone", milestone_freezer,)
register_freeze_implementation("epics.epic", epic_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("userstories.userstory", userstory_freezer)
register_freeze_implementation("issues.issue", issue_freezer) register_freeze_implementation("issues.issue", issue_freezer)
register_freeze_implementation("tasks.task", task_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("projects.project", project_values)
register_values_implementation("milestones.milestone", milestone_values) register_values_implementation("milestones.milestone", milestone_values)
register_values_implementation("epics.epic", epic_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("userstories.userstory", userstory_values)
register_values_implementation("issues.issue", issue_values) register_values_implementation("issues.issue", issue_values)
register_values_implementation("tasks.task", task_values) register_values_implementation("tasks.task", task_values)

View File

@ -98,7 +98,8 @@ class ProjectExtraInfoSerializerMixin(serializers.LightSerializer):
serialized_project = { serialized_project = {
"name": obj.project.name, "name": obj.project.name,
"slug": obj.project.slug, "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 self._serialized_project[obj.project_id] = serialized_project

View File

@ -336,6 +336,7 @@ def get_related_people(obj):
related_people = related_people.exclude(is_active=False) related_people = related_people.exclude(is_active=False)
related_people = related_people.exclude(is_system=True) related_people = related_people.exclude(is_system=True)
related_people = related_people.distinct() related_people = related_people.distinct()
return related_people return related_people

View File

@ -94,6 +94,7 @@ def _push_to_timeline(objects, instance: object, event_type: str, created_dateti
@app.task @app.task
def push_to_timelines(project_id, user_id, obj_app_label, obj_model_name, obj_id, event_type, def push_to_timelines(project_id, user_id, obj_app_label, obj_model_name, obj_id, event_type,
created_datetime, extra_data={}): created_datetime, extra_data={}):
ObjModel = apps.get_model(obj_app_label, obj_model_name) ObjModel = apps.get_model(obj_app_label, obj_model_name)
try: try:
obj = ObjModel.objects.get(id=obj_id) obj = ObjModel.objects.get(id=obj_id)
@ -266,13 +267,25 @@ def extract_epic_info(instance):
} }
def extract_userstory_info(instance): def extract_userstory_info(instance, include_project=False):
return { userstory_info = {
"id": instance.pk, "id": instance.pk,
"ref": instance.ref, "ref": instance.ref,
"subject": instance.subject, "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): def extract_issue_info(instance):
return { return {

View File

@ -55,6 +55,20 @@ def epic_timeline(instance, extra_data={}):
return result 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", "create")
@register_timeline_implementation("userstories.userstory", "change") @register_timeline_implementation("userstories.userstory", "change")
@register_timeline_implementation("userstories.userstory", "delete") @register_timeline_implementation("userstories.userstory", "delete")