From f982da7ebb95d41706eca2f6db025eae4a2397ba Mon Sep 17 00:00:00 2001 From: ikame Date: Thu, 27 Feb 2014 13:38:51 +0100 Subject: [PATCH] US #50: Neighbors nav for taskboard and kanban --- taiga/base/models.py | 30 ++++++++++++++++++++-------- taiga/projects/userstories/api.py | 2 +- taiga/projects/userstories/models.py | 10 +++++++++- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/taiga/base/models.py b/taiga/base/models.py index e30d6c76..c50758c5 100644 --- a/taiga/base/models.py +++ b/taiga/base/models.py @@ -23,7 +23,7 @@ class NeighborsMixin: if queryset is None: queryset = type(self).objects.get_queryset() if not self._get_queryset_order_by(queryset): - queryset = queryset.order_by(*self._meta.ordering) + queryset = queryset.order_by(*self._get_order_by()) queryset = queryset.filter(~Q(id=self.id)) return self._get_previous_neighbor(queryset), self._get_next_neighbor(queryset) @@ -31,6 +31,9 @@ class NeighborsMixin: def _get_queryset_order_by(self, queryset): return queryset.query.order_by or [] + def _get_order_by(self): + return self._meta.ordering + def _field(self, field): return getattr(self, field.lstrip("-")) @@ -42,25 +45,36 @@ class NeighborsMixin: operator = inc return field, operator + def _format(self, value): + if hasattr(value, "format"): + value = value.format(obj=self) + return value + def _or(self, conditions): - result = Q(**conditions[0]) - for condition in conditions: - result = result | Q(**condition) + condition = conditions[0] + result = Q(**{key: self._format(condition[key]) for key in condition}) + for condition in conditions[1:]: + result = result | Q(**{key: self._format(condition[key]) for key in condition}) return result - def _get_previous_neighbor(self, queryset): + def _get_prev_neighbor_filters(self, queryset): conds = [{"{}__{}".format(*self._filter(field, "lt", "gt")): self._field(field)} for field in self._get_queryset_order_by(queryset)] + return self._or(conds) + + def _get_previous_neighbor(self, queryset): try: - return queryset.filter(self._or(conds)).reverse()[0] + return queryset.filter(self._get_prev_neighbor_filters(queryset)).reverse()[0] except IndexError: return None - def _get_next_neighbor(self, queryset): + def _get_next_neighbor_filters(self, queryset): conds = [{"{}__{}".format(*self._filter(field, "gt", "lt")): self._field(field)} for field in self._get_queryset_order_by(queryset)] + return self._or(conds) + def _get_next_neighbor(self, queryset): try: - return queryset.filter(self._or(conds))[0] + return queryset.filter(self._get_next_neighbor_filters(queryset))[0] except IndexError: return None diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index 2ad7feed..3970b7bc 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -61,7 +61,7 @@ class UserStoryViewSet(NotificationSenderMixin, ModelCrudViewSet): permission_classes = (IsAuthenticated, permissions.UserStoryPermission) filter_backends = (filters.IsProjectMemberFilterBackend, filters.TagsFilter) - filter_fields = ['project', 'milestone', 'milestone__isnull'] + filter_fields = ['project', 'milestone', 'milestone__isnull', 'status'] create_notification_template = "create_userstory_notification" update_notification_template = "update_userstory_notification" diff --git a/taiga/projects/userstories/models.py b/taiga/projects/userstories/models.py index a03e8f65..cec2c97e 100644 --- a/taiga/projects/userstories/models.py +++ b/taiga/projects/userstories/models.py @@ -100,7 +100,7 @@ class UserStory(NeighborsMixin, WatchedMixin, BlockedMixin, models.Model): class Meta: verbose_name = "user story" verbose_name_plural = "user stories" - ordering = ["project", "order"] + ordering = ["project", "order", "ref"] unique_together = ("ref", "project") permissions = ( ("view_userstory", "Can view user story"), @@ -112,6 +112,14 @@ class UserStory(NeighborsMixin, WatchedMixin, BlockedMixin, models.Model): def __repr__(self): return "" % (self.id) + def _get_prev_neighbor_filters(self, queryset): + return self._or([{"order__lt": "{obj.order}"}, + {"order__lte": "{obj.order}", "ref__lt": "{obj.ref}"}]) + + def _get_next_neighbor_filters(self, queryset): + return self._or([{"order__gt": "{obj.order}"}, + {"order__gte": "{obj.order}", "ref__gt": "{obj.ref}"}]) + def get_role_points(self): return self.role_points