mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: issue filter views (#418)
* dev: views initiated * dev: refactor filtering logic * dev: move state grouping filter to util function * dev: view issues create endpoint and update on filters for time * dev: rename views to issue views * dev: rename in serilaizer and views * dev: update issue filters * dev: update filter * feat: create issue favorites * dev: update query keys * dev: update create and update method
This commit is contained in:
parent
46f6b61928
commit
b6ee197b40
@ -21,7 +21,7 @@ from .project import (
|
|||||||
)
|
)
|
||||||
from .state import StateSerializer
|
from .state import StateSerializer
|
||||||
from .shortcut import ShortCutSerializer
|
from .shortcut import ShortCutSerializer
|
||||||
from .view import ViewSerializer
|
from .view import IssueViewSerializer, IssueViewFavoriteSerializer
|
||||||
from .cycle import CycleSerializer, CycleIssueSerializer, CycleFavoriteSerializer
|
from .cycle import CycleSerializer, CycleIssueSerializer, CycleFavoriteSerializer
|
||||||
from .asset import FileAssetSerializer
|
from .asset import FileAssetSerializer
|
||||||
from .issue import (
|
from .issue import (
|
||||||
|
@ -1,14 +1,55 @@
|
|||||||
|
# Third party imports
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from .base import BaseSerializer
|
from .base import BaseSerializer
|
||||||
|
|
||||||
from plane.db.models import View
|
from plane.db.models import IssueView, IssueViewFavorite
|
||||||
|
from plane.utils.issue_filters import issue_filters
|
||||||
|
|
||||||
|
|
||||||
class ViewSerializer(BaseSerializer):
|
class IssueViewSerializer(BaseSerializer):
|
||||||
|
is_favorite = serializers.BooleanField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = View
|
model = IssueView
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"workspace",
|
"workspace",
|
||||||
"project",
|
"project",
|
||||||
|
"query",
|
||||||
|
]
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
query_params = validated_data.get("query_data", {})
|
||||||
|
|
||||||
|
if not bool(query_params):
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
{"query_data": ["Query data field cannot be empty"]}
|
||||||
|
)
|
||||||
|
|
||||||
|
validated_data["query"] = issue_filters(query_params, "POST")
|
||||||
|
return IssueView.objects.create(**validated_data)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
query_params = validated_data.get("query_data", {})
|
||||||
|
if not bool(query_params):
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
{"query_data": ["Query data field cannot be empty"]}
|
||||||
|
)
|
||||||
|
|
||||||
|
validated_data["query"] = issue_filters(query_params, "PATCH")
|
||||||
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
class IssueViewFavoriteSerializer(BaseSerializer):
|
||||||
|
view_detail = IssueViewSerializer(source="issue_view", read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = IssueViewFavorite
|
||||||
|
fields = "__all__"
|
||||||
|
read_only_fields = [
|
||||||
|
"workspace",
|
||||||
|
"project",
|
||||||
|
"user",
|
||||||
]
|
]
|
||||||
|
@ -79,7 +79,9 @@ from plane.api.views import (
|
|||||||
ShortCutViewSet,
|
ShortCutViewSet,
|
||||||
## End Shortcuts
|
## End Shortcuts
|
||||||
# Views
|
# Views
|
||||||
ViewViewSet,
|
IssueViewViewSet,
|
||||||
|
ViewIssuesEndpoint,
|
||||||
|
IssueViewFavoriteViewSet,
|
||||||
## End Views
|
## End Views
|
||||||
# Cycles
|
# Cycles
|
||||||
CycleViewSet,
|
CycleViewSet,
|
||||||
@ -474,7 +476,7 @@ urlpatterns = [
|
|||||||
# Views
|
# Views
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/views/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/views/",
|
||||||
ViewViewSet.as_view(
|
IssueViewViewSet.as_view(
|
||||||
{
|
{
|
||||||
"get": "list",
|
"get": "list",
|
||||||
"post": "create",
|
"post": "create",
|
||||||
@ -484,7 +486,7 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/views/<uuid:pk>/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/views/<uuid:pk>/",
|
||||||
ViewViewSet.as_view(
|
IssueViewViewSet.as_view(
|
||||||
{
|
{
|
||||||
"get": "retrieve",
|
"get": "retrieve",
|
||||||
"put": "update",
|
"put": "update",
|
||||||
@ -494,6 +496,30 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
name="project-view",
|
name="project-view",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/views/<uuid:view_id>/issues/",
|
||||||
|
ViewIssuesEndpoint.as_view(),
|
||||||
|
name="project-view-issues",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/user-favorite-views/",
|
||||||
|
IssueViewFavoriteViewSet.as_view(
|
||||||
|
{
|
||||||
|
"get": "list",
|
||||||
|
"post": "create",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
name="user-favorite-view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/user-favorite-views/<uuid:view_id>/",
|
||||||
|
IssueViewFavoriteViewSet.as_view(
|
||||||
|
{
|
||||||
|
"delete": "destroy",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
name="user-favorite-view",
|
||||||
|
),
|
||||||
## End Views
|
## End Views
|
||||||
## Cycles
|
## Cycles
|
||||||
path(
|
path(
|
||||||
|
@ -41,7 +41,7 @@ from .workspace import (
|
|||||||
)
|
)
|
||||||
from .state import StateViewSet
|
from .state import StateViewSet
|
||||||
from .shortcut import ShortCutViewSet
|
from .shortcut import ShortCutViewSet
|
||||||
from .view import ViewViewSet
|
from .view import IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet
|
||||||
from .cycle import (
|
from .cycle import (
|
||||||
CycleViewSet,
|
CycleViewSet,
|
||||||
CycleIssueViewSet,
|
CycleIssueViewSet,
|
||||||
|
@ -7,6 +7,7 @@ from itertools import groupby, chain
|
|||||||
from django.db.models import Prefetch, OuterRef, Func, F, Q
|
from django.db.models import Prefetch, OuterRef, Func, F, Q
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
|
||||||
|
|
||||||
# Third Party imports
|
# Third Party imports
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
@ -46,6 +47,7 @@ from plane.db.models import (
|
|||||||
)
|
)
|
||||||
from plane.bgtasks.issue_activites_task import issue_activity
|
from plane.bgtasks.issue_activites_task import issue_activity
|
||||||
from plane.utils.grouper import group_results
|
from plane.utils.grouper import group_results
|
||||||
|
from plane.utils.issue_filters import issue_filters
|
||||||
|
|
||||||
|
|
||||||
class IssueViewSet(BaseViewSet):
|
class IssueViewSet(BaseViewSet):
|
||||||
@ -172,18 +174,11 @@ class IssueViewSet(BaseViewSet):
|
|||||||
|
|
||||||
def list(self, request, slug, project_id):
|
def list(self, request, slug, project_id):
|
||||||
try:
|
try:
|
||||||
# Issue State groups
|
filters = issue_filters(request.query_params, "GET")
|
||||||
type = request.GET.get("type", "all")
|
|
||||||
group = ["backlog", "unstarted", "started", "completed", "cancelled"]
|
|
||||||
if type == "backlog":
|
|
||||||
group = ["backlog"]
|
|
||||||
if type == "active":
|
|
||||||
group = ["unstarted", "started"]
|
|
||||||
|
|
||||||
issue_queryset = (
|
issue_queryset = (
|
||||||
self.get_queryset()
|
self.get_queryset()
|
||||||
.order_by(request.GET.get("order_by", "created_at"))
|
.order_by(request.GET.get("order_by", "created_at"))
|
||||||
.filter(state__group__in=group)
|
.filter(**filters)
|
||||||
)
|
)
|
||||||
|
|
||||||
issues = IssueSerializer(issue_queryset, many=True).data
|
issues = IssueSerializer(issue_queryset, many=True).data
|
||||||
|
@ -1,14 +1,34 @@
|
|||||||
|
# Django imports
|
||||||
|
from django.db import IntegrityError
|
||||||
|
from django.db.models import Prefetch, OuterRef, Exists
|
||||||
|
|
||||||
|
# Third party imports
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
from sentry_sdk import capture_exception
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from . import BaseViewSet
|
from . import BaseViewSet, BaseAPIView
|
||||||
from plane.api.serializers import ViewSerializer
|
from plane.api.serializers import (
|
||||||
|
IssueViewSerializer,
|
||||||
|
IssueSerializer,
|
||||||
|
IssueViewFavoriteSerializer,
|
||||||
|
)
|
||||||
from plane.api.permissions import ProjectEntityPermission
|
from plane.api.permissions import ProjectEntityPermission
|
||||||
from plane.db.models import View
|
from plane.db.models import (
|
||||||
|
IssueView,
|
||||||
|
Issue,
|
||||||
|
IssueBlocker,
|
||||||
|
IssueLink,
|
||||||
|
CycleIssue,
|
||||||
|
ModuleIssue,
|
||||||
|
IssueViewFavorite,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ViewViewSet(BaseViewSet):
|
class IssueViewViewSet(BaseViewSet):
|
||||||
|
serializer_class = IssueViewSerializer
|
||||||
serializer_class = ViewSerializer
|
model = IssueView
|
||||||
model = View
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
ProjectEntityPermission,
|
ProjectEntityPermission,
|
||||||
]
|
]
|
||||||
@ -17,6 +37,12 @@ class ViewViewSet(BaseViewSet):
|
|||||||
serializer.save(project_id=self.kwargs.get("project_id"))
|
serializer.save(project_id=self.kwargs.get("project_id"))
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
subquery = IssueViewFavorite.objects.filter(
|
||||||
|
user=self.request.user,
|
||||||
|
view_id=OuterRef("pk"),
|
||||||
|
project_id=self.kwargs.get("project_id"),
|
||||||
|
workspace__slug=self.kwargs.get("slug"),
|
||||||
|
)
|
||||||
return self.filter_queryset(
|
return self.filter_queryset(
|
||||||
super()
|
super()
|
||||||
.get_queryset()
|
.get_queryset()
|
||||||
@ -25,5 +51,142 @@ class ViewViewSet(BaseViewSet):
|
|||||||
.filter(project__project_projectmember__member=self.request.user)
|
.filter(project__project_projectmember__member=self.request.user)
|
||||||
.select_related("project")
|
.select_related("project")
|
||||||
.select_related("workspace")
|
.select_related("workspace")
|
||||||
|
.annotate(is_favorite=Exists(subquery))
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ViewIssuesEndpoint(BaseAPIView):
|
||||||
|
permission_classes = [
|
||||||
|
ProjectEntityPermission,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get(self, request, slug, project_id, view_id):
|
||||||
|
try:
|
||||||
|
view = IssueView.objects.get(pk=view_id)
|
||||||
|
queries = view.query
|
||||||
|
|
||||||
|
issues = (
|
||||||
|
Issue.objects.filter(
|
||||||
|
**queries, project_id=project_id, workspace__slug=slug
|
||||||
|
)
|
||||||
|
.select_related("project")
|
||||||
|
.select_related("workspace")
|
||||||
|
.select_related("state")
|
||||||
|
.select_related("parent")
|
||||||
|
.prefetch_related("assignees")
|
||||||
|
.prefetch_related("labels")
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"blocked_issues",
|
||||||
|
queryset=IssueBlocker.objects.select_related(
|
||||||
|
"blocked_by", "block"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"blocker_issues",
|
||||||
|
queryset=IssueBlocker.objects.select_related(
|
||||||
|
"block", "blocked_by"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"issue_cycle",
|
||||||
|
queryset=CycleIssue.objects.select_related("cycle", "issue"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"issue_module",
|
||||||
|
queryset=ModuleIssue.objects.select_related(
|
||||||
|
"module", "issue"
|
||||||
|
).prefetch_related("module__members"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"issue_link",
|
||||||
|
queryset=IssueLink.objects.select_related(
|
||||||
|
"issue"
|
||||||
|
).select_related("created_by"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer = IssueSerializer(issues, many=True)
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
except IssueView.DoesNotExist:
|
||||||
|
return Response(
|
||||||
|
{"error": "Issue View does not exist"}, status=status.HTTP_404_NOT_FOUND
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
capture_exception(e)
|
||||||
|
return Response(
|
||||||
|
{"error": "Something went wrong please try again later"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class IssueViewFavoriteViewSet(BaseViewSet):
|
||||||
|
serializer_class = IssueViewFavoriteSerializer
|
||||||
|
model = IssueViewFavorite
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.filter_queryset(
|
||||||
|
super()
|
||||||
|
.get_queryset()
|
||||||
|
.filter(workspace__slug=self.kwargs.get("slug"))
|
||||||
|
.filter(user=self.request.user)
|
||||||
|
.select_related("view")
|
||||||
|
)
|
||||||
|
|
||||||
|
def create(self, request, slug, project_id):
|
||||||
|
try:
|
||||||
|
serializer = IssueViewFavoriteSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save(user=request.user, project_id=project_id)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
except IntegrityError as e:
|
||||||
|
if "already exists" in str(e):
|
||||||
|
return Response(
|
||||||
|
{"error": "The view is already added to favorites"},
|
||||||
|
status=status.HTTP_410_GONE,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
capture_exception(e)
|
||||||
|
return Response(
|
||||||
|
{"error": "Something went wrong please try again later"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
capture_exception(e)
|
||||||
|
return Response(
|
||||||
|
{"error": "Something went wrong please try again later"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
def destroy(self, request, slug, project_id, view_id):
|
||||||
|
try:
|
||||||
|
view_favourite = IssueViewFavorite.objects.get(
|
||||||
|
project=project_id,
|
||||||
|
user=request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
view_id=view_id,
|
||||||
|
)
|
||||||
|
view_favourite.delete()
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
except IssueViewFavorite.DoesNotExist:
|
||||||
|
return Response(
|
||||||
|
{"error": "View is not in favorites"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
capture_exception(e)
|
||||||
|
return Response(
|
||||||
|
{"error": "Something went wrong please try again later"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
@ -44,7 +44,7 @@ from .cycle import Cycle, CycleIssue, CycleFavorite
|
|||||||
|
|
||||||
from .shortcut import Shortcut
|
from .shortcut import Shortcut
|
||||||
|
|
||||||
from .view import View
|
from .view import IssueView, IssueViewFavorite
|
||||||
|
|
||||||
from .module import Module, ModuleMember, ModuleIssue, ModuleLink, ModuleFavorite
|
from .module import Module, ModuleMember, ModuleIssue, ModuleLink, ModuleFavorite
|
||||||
|
|
||||||
|
@ -1,22 +1,48 @@
|
|||||||
# Django imports
|
# Django imports
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
# Module import
|
# Module import
|
||||||
from . import ProjectBaseModel
|
from . import ProjectBaseModel
|
||||||
|
|
||||||
|
|
||||||
class View(ProjectBaseModel):
|
class IssueView(ProjectBaseModel):
|
||||||
name = models.CharField(max_length=255, verbose_name="View Name")
|
name = models.CharField(max_length=255, verbose_name="View Name")
|
||||||
description = models.TextField(verbose_name="View Description", blank=True)
|
description = models.TextField(verbose_name="View Description", blank=True)
|
||||||
query = models.JSONField(verbose_name="View Query")
|
query = models.JSONField(verbose_name="View Query")
|
||||||
|
access = models.PositiveSmallIntegerField(
|
||||||
|
default=1, choices=((0, "Private"), (1, "Public"))
|
||||||
|
)
|
||||||
|
query_data = models.JSONField(default=dict)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "View"
|
verbose_name = "Issue View"
|
||||||
verbose_name_plural = "Views"
|
verbose_name_plural = "Issue Views"
|
||||||
db_table = "views"
|
db_table = "issue_views"
|
||||||
ordering = ("-created_at",)
|
ordering = ("-created_at",)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return name of the View"""
|
"""Return name of the View"""
|
||||||
return f"{self.name} <{self.project.name}>"
|
return f"{self.name} <{self.project.name}>"
|
||||||
|
|
||||||
|
|
||||||
|
class IssueViewFavorite(ProjectBaseModel):
|
||||||
|
user = models.ForeignKey(
|
||||||
|
settings.AUTH_USER_MODEL,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="user_view_favorites",
|
||||||
|
)
|
||||||
|
view = models.ForeignKey(
|
||||||
|
"db.IssueView", on_delete=models.CASCADE, related_name="view_favorites"
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ["view", "user"]
|
||||||
|
verbose_name = "View Favorite"
|
||||||
|
verbose_name_plural = "View Favorites"
|
||||||
|
db_table = "view_favorites"
|
||||||
|
ordering = ("-created_at",)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return user and the view"""
|
||||||
|
return f"{self.user.email} <{self.view.name}>"
|
||||||
|
214
apiserver/plane/utils/issue_filters.py
Normal file
214
apiserver/plane/utils/issue_filters.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
from django.utils.timezone import make_aware
|
||||||
|
from django.utils.dateparse import parse_datetime
|
||||||
|
|
||||||
|
|
||||||
|
def filter_state(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
states = params.get("state").split(",")
|
||||||
|
if len(states) and "" not in states:
|
||||||
|
filter["state__in"] = states
|
||||||
|
else:
|
||||||
|
if len(params.get("state")):
|
||||||
|
filter["state__in"] = params.get("state")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_priority(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
priorties = params.get("priority").split(",")
|
||||||
|
if len(priorties) and "" not in priorties:
|
||||||
|
filter["priority__in"] = priorties
|
||||||
|
else:
|
||||||
|
if len(params.get("priority")):
|
||||||
|
filter["priority__in"] = params.get("priority")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_parent(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
parents = params.get("parent").split(",")
|
||||||
|
if len(parents) and "" not in parents:
|
||||||
|
filter["parent__in"] = parents
|
||||||
|
else:
|
||||||
|
if len(params.get("parent")):
|
||||||
|
filter["parent__in"] = params.get("parent")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_labels(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
labels = params.get("labels").split(",")
|
||||||
|
if len(labels) and "" not in labels:
|
||||||
|
filter["labels__in"] = labels
|
||||||
|
else:
|
||||||
|
if len(params.get("labels")):
|
||||||
|
filter["labels__in"] = params.get("labels")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_assignees(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
assignees = params.get("assignees").split(",")
|
||||||
|
if len(assignees) and "" not in assignees:
|
||||||
|
filter["assignees__in"] = assignees
|
||||||
|
else:
|
||||||
|
if len(params.get("assignees")):
|
||||||
|
filter["assignees__in"] = params.get("assignees")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_created_by(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
created_bys = params.get("created_by").split(",")
|
||||||
|
if len(created_bys) and "" not in created_bys:
|
||||||
|
filter["created_by__in"] = created_bys
|
||||||
|
else:
|
||||||
|
if len(params.get("created_by")):
|
||||||
|
filter["created_by__in"] = params.get("created_by")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_name(params, filter, method):
|
||||||
|
if params.get("name", "") != "":
|
||||||
|
filter["name__icontains"] = params.get("name")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_created_at(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
created_ats = params.get("created_at").split(",")
|
||||||
|
if len(created_ats) and "" not in created_ats:
|
||||||
|
for query in created_ats:
|
||||||
|
created_at_query = query.split(";")
|
||||||
|
if len(created_at_query) == 2 and "after" in created_at_query:
|
||||||
|
filter["created_at__date__gte"] = created_at_query[0]
|
||||||
|
else:
|
||||||
|
filter["created_at__date__lte"] = created_at_query[0]
|
||||||
|
else:
|
||||||
|
if len(params.get("created_at")):
|
||||||
|
for query in params.get("created_at"):
|
||||||
|
if query.get("timeline", "after") == "after":
|
||||||
|
filter["created_at__date__gte"] = query.get("datetime")
|
||||||
|
else:
|
||||||
|
filter["created_at__date__lte"] = query.get("datetime")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_updated_at(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
updated_bys = params.get("updated_at").split(",")
|
||||||
|
if len(updated_bys) and "" not in updated_bys:
|
||||||
|
for query in updated_bys:
|
||||||
|
updated_at_query = query.split(";")
|
||||||
|
if len(updated_at_query) == 2 and "after" in updated_at_query:
|
||||||
|
filter["updated_at__date__gte"] = updated_at_query[0]
|
||||||
|
else:
|
||||||
|
filter["updated_at__date__lte"] = updated_at_query[0]
|
||||||
|
else:
|
||||||
|
if len(params.get("updated_at")):
|
||||||
|
for query in params.get("updated_at"):
|
||||||
|
if query.get("timeline", "after") == "after":
|
||||||
|
filter["updated_at__date__gte"] = query.get("datetime")
|
||||||
|
else:
|
||||||
|
filter["updated_at__date__lte"] = query.get("datetime")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_start_date(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
start_dates = params.get("start_date").split(";")
|
||||||
|
if len(start_dates) and "" not in start_dates:
|
||||||
|
for query in start_dates:
|
||||||
|
start_date_query = query.split(";")
|
||||||
|
if len(start_date_query) == 2 and "after" in start_date_query:
|
||||||
|
filter["start_date__date__gte"] = start_date_query[0]
|
||||||
|
else:
|
||||||
|
filter["start_date__date__lte"] = start_date_query[0]
|
||||||
|
else:
|
||||||
|
if len(params.get("start_date")):
|
||||||
|
for query in params.get("start_date"):
|
||||||
|
if query.get("timeline", "after") == "after":
|
||||||
|
filter["start_date__date__gte"] = query.get("datetime")
|
||||||
|
else:
|
||||||
|
filter["start_date__date__lte"] = query.get("datetime")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_target_date(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
target_dates = params.get("target_date").split(";")
|
||||||
|
if len(target_dates) and "" not in target_dates:
|
||||||
|
for query in target_dates:
|
||||||
|
target_date_query = query.split(";")
|
||||||
|
if len(target_date_query) == 2 and "after" in target_date_query:
|
||||||
|
filter["target_date__date__gte"] = target_date_query[0]
|
||||||
|
else:
|
||||||
|
filter["target_date__date__lte"] = target_date_query[0]
|
||||||
|
else:
|
||||||
|
if len(params.get("target_date")):
|
||||||
|
for query in params.get("target_date"):
|
||||||
|
if query.get("timeline", "after") == "after":
|
||||||
|
filter["target_date__date__gte"] = query.get("datetime")
|
||||||
|
else:
|
||||||
|
filter["target_date__date__lte"] = query.get("datetime")
|
||||||
|
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_completed_at(params, filter, method):
|
||||||
|
if method == "GET":
|
||||||
|
completed_ats = params.get("completed_at").split(",")
|
||||||
|
if len(completed_ats) and "" not in completed_ats:
|
||||||
|
for query in completed_ats:
|
||||||
|
completed_at_query = query.split(";")
|
||||||
|
if len(completed_at_query) == 2 and "after" in completed_at_query:
|
||||||
|
filter["completed_at__date__gte"] = completed_at_query[0]
|
||||||
|
else:
|
||||||
|
filter["completed_at__lte"] = completed_at_query[0]
|
||||||
|
else:
|
||||||
|
if len(params.get("completed_at")):
|
||||||
|
for query in params.get("completed_at"):
|
||||||
|
if query.get("timeline", "after") == "after":
|
||||||
|
filter["completed_at__date__gte"] = query.get("datetime")
|
||||||
|
else:
|
||||||
|
filter["completed_at__lte"] = query.get("datetime")
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def filter_issue_state_type(params, filter, method):
|
||||||
|
type = params.get("type", "all")
|
||||||
|
group = ["backlog", "unstarted", "started", "completed", "cancelled"]
|
||||||
|
if type == "backlog":
|
||||||
|
group = ["backlog"]
|
||||||
|
if type == "active":
|
||||||
|
group = ["unstarted", "started"]
|
||||||
|
|
||||||
|
filter["state__group__in"] = group
|
||||||
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def issue_filters(query_params, method):
|
||||||
|
filter = dict()
|
||||||
|
|
||||||
|
ISSUE_FILTER = {
|
||||||
|
"state": filter_state,
|
||||||
|
"priority": filter_priority,
|
||||||
|
"parent": filter_parent,
|
||||||
|
"labels": filter_labels,
|
||||||
|
"assignees": filter_assignees,
|
||||||
|
"created_by": filter_created_by,
|
||||||
|
"name": filter_name,
|
||||||
|
"created_at": filter_created_at,
|
||||||
|
"updated_at": filter_updated_at,
|
||||||
|
"start_date": filter_start_date,
|
||||||
|
"target_date": filter_target_date,
|
||||||
|
"completed_at": filter_completed_at,
|
||||||
|
"type": filter_issue_state_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in ISSUE_FILTER.items():
|
||||||
|
if key in query_params:
|
||||||
|
func = value
|
||||||
|
func(query_params, filter, method)
|
||||||
|
|
||||||
|
return filter
|
Loading…
Reference in New Issue
Block a user