From e2f6245fbbca7dc5e516bb7343ce10ee8420f0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Wed, 27 Jul 2016 19:00:32 +0200 Subject: [PATCH] Add epic order in userstories if filter by epic ide is enabled --- taiga/base/filters.py | 11 +++++++-- taiga/projects/userstories/api.py | 6 ++++- taiga/projects/userstories/filters.py | 7 +++++- taiga/projects/userstories/serializers.py | 12 +++++++++ taiga/projects/userstories/utils.py | 30 +++++++++++++++++++++-- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/taiga/base/filters.py b/taiga/base/filters.py index a30e2dcf..06274128 100644 --- a/taiga/base/filters.py +++ b/taiga/base/filters.py @@ -337,10 +337,16 @@ class IsProjectAdminFromWebhookLogFilterBackend(FilterBackend, BaseIsProjectAdmi ##################################################################### class BaseRelatedFieldsFilter(FilterBackend): - def __init__(self, filter_name=None): + filter_name = None + param_name = None + + def __init__(self, filter_name=None, param_name=None): if filter_name: self.filter_name = filter_name + if param_name: + self.param_name = param_name + def _prepare_filter_data(self, query_param_value): def _transform_value(value): try: @@ -355,7 +361,8 @@ class BaseRelatedFieldsFilter(FilterBackend): return list(values) def _get_queryparams(self, params): - raw_value = params.get(self.filter_name, None) + param_name = self.param_name or self.filter_name + raw_value = params.get(param_name, None) if raw_value: value = self._prepare_filter_data(raw_value) diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index 23a471fb..758fa98c 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -60,6 +60,7 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi permission_classes = (permissions.UserStoryPermission,) filter_backends = (base_filters.CanViewUsFilterBackend, filters.EpicsFilter, + filters.EpicFilter, base_filters.OwnersFilter, base_filters.AssignedToFilter, base_filters.StatusesFilter, @@ -80,6 +81,7 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi order_by_fields = ["backlog_order", "sprint_order", "kanban_order", + "epic_order", "total_voters"] def get_serializer_class(self, *args, **kwargs): @@ -102,9 +104,11 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi include_attachments = "include_attachments" in self.request.QUERY_PARAMS include_tasks = "include_tasks" in self.request.QUERY_PARAMS + epic_id = self.request.QUERY_PARAMS.get("epic", None) qs = attach_extra_info(qs, user=self.request.user, include_attachments=include_attachments, - include_tasks=include_tasks) + include_tasks=include_tasks, + epic_id=epic_id) return qs diff --git a/taiga/projects/userstories/filters.py b/taiga/projects/userstories/filters.py index 5f877618..f061667e 100644 --- a/taiga/projects/userstories/filters.py +++ b/taiga/projects/userstories/filters.py @@ -20,5 +20,10 @@ from taiga.base import filters +class EpicFilter(filters.BaseRelatedFieldsFilter): + filter_name = "epics" + param_name = "epic" + + class EpicsFilter(filters.BaseRelatedFieldsFilter): - filter_name = 'epics' + filter_name = "epics" diff --git a/taiga/projects/userstories/serializers.py b/taiga/projects/userstories/serializers.py index 97fcea42..b7c43466 100644 --- a/taiga/projects/userstories/serializers.py +++ b/taiga/projects/userstories/serializers.py @@ -78,8 +78,20 @@ class UserStoryListSerializer(ProjectExtraInfoSerializerMixin, comment = MethodField() origin_issue = OriginIssueSerializer(attr="generated_from_issue") epics = MethodField() + epic_order = MethodField() tasks = MethodField() + def get_epic_order(self, obj): + include_epic_order = getattr(obj, "include_epic_order", False) + + if include_epic_order: + assert hasattr(obj, "epic_order"), "instance must have a epic_order attribute" + + if not include_epic_order or obj.epic_order is None: + return None + + return obj.epic_order + def get_epics(self, obj): assert hasattr(obj, "epics_attr"), "instance must have a epics_attr attribute" return obj.epics_attr diff --git a/taiga/projects/userstories/utils.py b/taiga/projects/userstories/utils.py index ea7637f4..ef5e8ba0 100644 --- a/taiga/projects/userstories/utils.py +++ b/taiga/projects/userstories/utils.py @@ -120,14 +120,36 @@ def attach_epics(queryset, as_field="epics_attr"): FROM "epics_relateduserstory" INNER JOIN "epics_epic" ON "epics_epic"."id" = "epics_relateduserstory"."epic_id" INNER JOIN "projects_project" ON "projects_project"."id" = "epics_epic"."project_id" - WHERE "epics_relateduserstory"."user_story_id" = {tbl}.id) t""" + WHERE "epics_relateduserstory"."user_story_id" = {tbl}.id + ORDER BY "projects_project"."name", "epics_epic"."ref") t""" sql = sql.format(tbl=model._meta.db_table) queryset = queryset.extra(select={as_field: sql}) return queryset -def attach_extra_info(queryset, user=None, include_attachments=False, include_tasks=False): +def attach_epic_order(queryset, epic_id, as_field="epic_order"): + """Attach epic_order column to each object of the queryset. + + :param queryset: A Django user stories queryset object. + :param epic_id: Order related to this epic. + :param as_field: Attach order as an attribute with this name. + + :return: Queryset object with the additional `as_field` field. + """ + + model = queryset.model + sql = """SELECT "epics_relateduserstory"."order" AS "epic_order" + FROM "epics_relateduserstory" + WHERE "epics_relateduserstory"."user_story_id" = {tbl}.id and + "epics_relateduserstory"."epic_id" = {epic_id}""" + + sql = sql.format(tbl=model._meta.db_table, epic_id=epic_id) + queryset = queryset.extra(select={as_field: sql}) + return queryset + + +def attach_extra_info(queryset, user=None, include_attachments=False, include_tasks=False, epic_id=None): queryset = attach_total_points(queryset) queryset = attach_role_points(queryset) queryset = attach_epics(queryset) @@ -140,6 +162,10 @@ def attach_extra_info(queryset, user=None, include_attachments=False, include_ta queryset = attach_tasks(queryset) queryset = queryset.extra(select={"include_tasks": "True"}) + if epic_id is not None: + queryset = attach_epic_order(queryset, epic_id) + queryset = queryset.extra(select={"include_epic_order": "True"}) + queryset = attach_total_voters_to_queryset(queryset) queryset = attach_watchers_to_queryset(queryset) queryset = attach_total_watchers_to_queryset(queryset)