From d47efaa0f0f752693759eae9363f7b5a1ab9a863 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Mon, 25 Sep 2023 16:51:59 +0530 Subject: [PATCH 1/3] dev: remove auto filter endpoint --- apiserver/plane/api/urls.py | 6 ---- apiserver/plane/api/views/__init__.py | 2 +- apiserver/plane/api/views/view.py | 45 -------------------------- apiserver/plane/utils/issue_filters.py | 4 --- 4 files changed, 1 insertion(+), 56 deletions(-) diff --git a/apiserver/plane/api/urls.py b/apiserver/plane/api/urls.py index c10c4a7456..771c131ed0 100644 --- a/apiserver/plane/api/urls.py +++ b/apiserver/plane/api/urls.py @@ -105,7 +105,6 @@ from plane.api.views import ( GlobalViewViewSet, GlobalViewIssuesViewSet, IssueViewViewSet, - ViewIssuesEndpoint, IssueViewFavoriteViewSet, ## End Views # Cycles @@ -649,11 +648,6 @@ urlpatterns = [ ), name="project-view", ), - path( - "workspaces//projects//views//issues/", - ViewIssuesEndpoint.as_view(), - name="project-view-issues", - ), path( "workspaces//views/", GlobalViewViewSet.as_view( diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index c03d6d5b7f..7e89c37f1e 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -56,7 +56,7 @@ from .workspace import ( LeaveWorkspaceEndpoint, ) from .state import StateViewSet -from .view import GlobalViewViewSet, GlobalViewIssuesViewSet, IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet +from .view import GlobalViewViewSet, GlobalViewIssuesViewSet, IssueViewViewSet, IssueViewFavoriteViewSet from .cycle import ( CycleViewSet, CycleIssueViewSet, diff --git a/apiserver/plane/api/views/view.py b/apiserver/plane/api/views/view.py index b6f1d7c4b7..bf47d1e4b3 100644 --- a/apiserver/plane/api/views/view.py +++ b/apiserver/plane/api/views/view.py @@ -243,51 +243,6 @@ class IssueViewViewSet(BaseViewSet): ) -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 - - filters = issue_filters(request.query_params, "GET") - - issues = ( - Issue.issue_objects.filter( - **queries, project_id=project_id, workspace__slug=slug - ) - .filter(**filters) - .select_related("project") - .select_related("workspace") - .select_related("state") - .select_related("parent") - .prefetch_related("assignees") - .prefetch_related("labels") - .prefetch_related( - Prefetch( - "issue_reactions", - queryset=IssueReaction.objects.select_related("actor"), - ) - ) - ) - - serializer = IssueLiteSerializer(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 diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index 3a869113cd..eec5289166 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -1,7 +1,3 @@ -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(",") From 608ba9d5cbefeb6d60e6c16bbdb96dc5de69e67d Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Tue, 26 Sep 2023 16:33:49 +0530 Subject: [PATCH 2/3] chore: udpate date filters to support dynamic options --- apiserver/plane/utils/issue_filters.py | 250 +++++++++++++++++++++---- 1 file changed, 212 insertions(+), 38 deletions(-) diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index eec5289166..09b55d96f2 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -1,3 +1,38 @@ +import re +from datetime import timedelta +from django.utils import timezone + +# The date from pattern +pattern = re.compile(r"\d+_(weeks|months)$") + + +# Get the 2_weeks, 3_months +def date_filter(filter, duration, subsequent, term, date_filter, offset): + now = timezone.now().date() + if term == "months": + if subsequent == "after": + if offset == "fromnow": + filter[f"{date_filter}__gte"] = now + timedelta(days=duration * 30) + else: + filter[f"{date_filter}__gte"] = now - timedelta(days=duration * 30) + else: + if offset == "fromnow": + filter[f"{date_filter}__lte"] = now + timedelta(days=duration * 30) + else: + filter[f"{date_filter}__lte"] = now - timedelta(days=duration * 30) + if term == "weeks": + if subsequent == "after": + if offset == "fromnow": + filter[f"{date_filter}__gte"] = now + timedelta(weeks=duration) + else: + filter[f"{date_filter}__gte"] = now - timedelta(weeks=duration) + else: + if offset == "fromnow": + filter[f"{date_filter}__lte"] = now + timedelta(days=duration) + else: + filter[f"{date_filter}__lte"] = now - timedelta(days=duration) + + def filter_state(params, filter, method): if method == "GET": states = params.get("state").split(",") @@ -95,18 +130,46 @@ def filter_created_at(params, filter, method): 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] + if len(created_at_query) >= 2: + match = pattern.match(created_at_query[0]) + if match: + if len(created_at_query) == 3: + digit, term = created_at_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=created_at_query[1], + term=term, + date_filter="created_at__date", + offset=created_at_query[2], + ) + else: + if "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 params.get("created_at", None) and len(params.get("created_at")): for query in params.get("created_at"): 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] + if len(created_at_query) == 2: + match = pattern.match(created_at_query[0]) + if match: + if len(created_at_query) == 3: + digit, term = created_at_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=created_at_query[1], + term=term, + date_filter="created_at__date", + offset=created_at_query[2], + ) + else: + if "after" in created_at_query: + filter["created_at__date__gte"] = created_at_query[0] + else: + filter["created_at__date__lte"] = created_at_query[0] return filter @@ -116,18 +179,46 @@ def filter_updated_at(params, filter, method): if len(updated_ats) and "" not in updated_ats: for query in updated_ats: 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] + if len(updated_at_query) == 2: + match = pattern.match(updated_at_query[0]) + if match: + if len(updated_at_query) == 3: + digit, term = updated_at_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=updated_at_query[1], + term=term, + date_filter="updated_at__date", + offset=updated_at_query[2], + ) + else: + if "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 params.get("updated_at", None) and len(params.get("updated_at")): for query in params.get("updated_at"): 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] + if len(updated_at_query) == 2: + match = pattern.match(updated_at_query[0]) + if match: + if len(updated_at_query) == 3: + digit, term = updated_at_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=updated_at_query[1], + term=term, + date_filter="updated_at__date", + offset=updated_at_query[2], + ) + else: + if "after" in updated_at_query: + filter["updated_at__date__gte"] = updated_at_query[0] + else: + filter["updated_at__date__lte"] = updated_at_query[0] return filter @@ -137,18 +228,46 @@ def filter_start_date(params, filter, method): 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__gte"] = start_date_query[0] - else: - filter["start_date__lte"] = start_date_query[0] + if len(start_date_query) >= 2: + match = pattern.match(start_date_query[0]) + if match: + if len(start_date_query) == 3: + digit, term = start_date_query[0].split("_") + date_filter( + filter=filter, + duration=float(digit), + subsequent=start_date_query[1], + term=term, + date_filter="start_date", + offset=start_date_query[2], + ) + else: + if "after" in start_date_query: + filter["start_date__gte"] = start_date_query[0] + else: + filter["start_date__lte"] = start_date_query[0] else: if params.get("start_date", None) and len(params.get("start_date")): for query in params.get("start_date"): start_date_query = query.split(";") - if len(start_date_query) == 2 and "after" in start_date_query: - filter["start_date__gte"] = start_date_query[0] - else: - filter["start_date__lte"] = start_date_query[0] + if len(start_date_query) == 2: + match = pattern.match(start_date_query[0]) + if match: + if len(start_date_query) == 3: + digit, term = start_date_query[0].split("_") + date_filter( + filter=filter, + duration=float(digit), + subsequent=start_date_query[1], + term=term, + date_filter="start_date", + offset=start_date_query[2], + ) + else: + if "after" in start_date_query: + filter["start_date__gte"] = start_date_query[0] + else: + filter["start_date__lte"] = start_date_query[0] return filter @@ -158,18 +277,46 @@ def filter_target_date(params, filter, method): 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__gt"] = target_date_query[0] - else: - filter["target_date__lt"] = target_date_query[0] + if len(target_date_query) == 2: + match = pattern.match(target_date_query[0]) + if match: + if len(target_date_query) == 3: + digit, term = target_date_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=target_date_query[1], + term=term, + date_filter="target_date", + offset=target_date_query[2], + ) + else: + if "after" in target_date_query: + filter["target_date__gt"] = target_date_query[0] + else: + filter["target_date__lt"] = target_date_query[0] else: if params.get("target_date", None) and len(params.get("target_date")): for query in params.get("target_date"): target_date_query = query.split(";") - if len(target_date_query) == 2 and "after" in target_date_query: - filter["target_date__gt"] = target_date_query[0] - else: - filter["target_date__lt"] = target_date_query[0] + if len(target_date_query) == 2: + match = pattern.match(target_date_query[0]) + if match: + if len(target_date_query) == 3: + digit, term = target_date_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=target_date_query[1], + term=term, + date_filter="target_date", + offset=target_date_query[2], + ) + else: + if "after" in target_date_query: + filter["target_date__gt"] = target_date_query[0] + else: + filter["target_date__lt"] = target_date_query[0] return filter @@ -180,18 +327,45 @@ def filter_completed_at(params, filter, method): 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] + if len(completed_at_query) == 2: + match = pattern.match(completed_at_query[0]) + if match: + if len(completed_at_query) == 3: + digit, term = completed_at_query[0].split("_") + date_filter( + filter=filter, + duration=digit, + subsequent=completed_at_query[1], + term=term, + date_filter="completed_at__date", + offset=completed_at_query[2], + ) else: - filter["completed_at__lte"] = completed_at_query[0] + if "after" in completed_at_query: + filter["completed_at__date__gte"] = completed_at_query[0] + else: + filter["completed_at__date__lte"] = completed_at_query[0] else: if params.get("completed_at", None) and len(params.get("completed_at")): for query in params.get("completed_at"): 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] + if len(completed_at_query) == 2: + match = pattern.match(completed_at_query[0]) + if match: + digit, term = match.group(1), match.group(2) + date_filter( + filter=filter, + duration=digit, + subsequent=completed_at_query[1], + term=term, + date_filter="completed_at__date", + offset=completed_at_query[2], + ) else: - filter["completed_at__lte"] = completed_at_query[0] + if "after" in completed_at_query: + filter["completed_at__date__gte"] = completed_at_query[0] + else: + filter["completed_at__date__lte"] = completed_at_query[0] return filter From 42d39194592f3f1cce21089fb06312b3beb86833 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Wed, 27 Sep 2023 14:33:41 +0530 Subject: [PATCH 3/3] dev: refactor date filters to a single function --- apiserver/plane/api/views/issue.py | 4 - apiserver/plane/utils/issue_filters.py | 238 ++++--------------------- 2 files changed, 37 insertions(+), 205 deletions(-) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 003a8ae320..280d929af7 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -24,8 +24,6 @@ from django.core.serializers.json import DjangoJSONEncoder from django.utils.decorators import method_decorator from django.views.decorators.gzip import gzip_page from django.db import IntegrityError -from django.conf import settings -from django.db import IntegrityError # Third Party imports from rest_framework.response import Response @@ -58,7 +56,6 @@ from plane.api.serializers import ( IssuePublicSerializer, ) from plane.api.permissions import ( - WorkspaceEntityPermission, ProjectEntityPermission, WorkSpaceAdminPermission, ProjectMemberPermission, @@ -86,7 +83,6 @@ from plane.db.models import ( from plane.bgtasks.issue_activites_task import issue_activity from plane.utils.grouper import group_results from plane.utils.issue_filters import issue_filters -from plane.bgtasks.export_task import issue_export_task class IssueViewSet(BaseViewSet): diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index 09b55d96f2..edcfa29301 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -7,7 +7,7 @@ pattern = re.compile(r"\d+_(weeks|months)$") # Get the 2_weeks, 3_months -def date_filter(filter, duration, subsequent, term, date_filter, offset): +def string_date_filter(filter, duration, subsequent, term, date_filter, offset): now = timezone.now().date() if term == "months": if subsequent == "after": @@ -33,6 +33,32 @@ def date_filter(filter, duration, subsequent, term, date_filter, offset): filter[f"{date_filter}__lte"] = now - timedelta(days=duration) +def date_filter(filter, date_term, queries): + """ + Handle all date filters + """ + for query in queries: + date_query = query.split(";") + if len(date_query) >= 2: + match = pattern.match(date_query[0]) + if match: + if len(date_query) == 3: + digit, term = date_query[0].split("_") + string_date_filter( + filter=filter, + duration=int(digit), + subsequent=date_query[1], + term=term, + date_filter="created_at__date", + offset=date_query[2], + ) + else: + if "after" in date_query: + filter[f"{date_term}__gte"] = date_query[0] + else: + filter[f"{date_term}__lte"] = date_query[0] + + def filter_state(params, filter, method): if method == "GET": states = params.get("state").split(",") @@ -128,48 +154,10 @@ 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: - match = pattern.match(created_at_query[0]) - if match: - if len(created_at_query) == 3: - digit, term = created_at_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=created_at_query[1], - term=term, - date_filter="created_at__date", - offset=created_at_query[2], - ) - else: - if "after" in created_at_query: - filter["created_at__date__gte"] = created_at_query[0] - else: - filter["created_at__date__lte"] = created_at_query[0] + date_filter(filter=filter, date_term="created_at__date", queries=created_ats) else: if params.get("created_at", None) and len(params.get("created_at")): - for query in params.get("created_at"): - created_at_query = query.split(";") - if len(created_at_query) == 2: - match = pattern.match(created_at_query[0]) - if match: - if len(created_at_query) == 3: - digit, term = created_at_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=created_at_query[1], - term=term, - date_filter="created_at__date", - offset=created_at_query[2], - ) - else: - if "after" in created_at_query: - filter["created_at__date__gte"] = created_at_query[0] - else: - filter["created_at__date__lte"] = created_at_query[0] + date_filter(filter=filter, date_term="created_at__date", queries=params.get("created_at", [])) return filter @@ -177,48 +165,10 @@ def filter_updated_at(params, filter, method): if method == "GET": updated_ats = params.get("updated_at").split(",") if len(updated_ats) and "" not in updated_ats: - for query in updated_ats: - updated_at_query = query.split(";") - if len(updated_at_query) == 2: - match = pattern.match(updated_at_query[0]) - if match: - if len(updated_at_query) == 3: - digit, term = updated_at_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=updated_at_query[1], - term=term, - date_filter="updated_at__date", - offset=updated_at_query[2], - ) - else: - if "after" in updated_at_query: - filter["updated_at__date__gte"] = updated_at_query[0] - else: - filter["updated_at__date__lte"] = updated_at_query[0] + date_filter(filter=filter, date_term="created_at__date", queries=updated_ats) else: if params.get("updated_at", None) and len(params.get("updated_at")): - for query in params.get("updated_at"): - updated_at_query = query.split(";") - if len(updated_at_query) == 2: - match = pattern.match(updated_at_query[0]) - if match: - if len(updated_at_query) == 3: - digit, term = updated_at_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=updated_at_query[1], - term=term, - date_filter="updated_at__date", - offset=updated_at_query[2], - ) - else: - if "after" in updated_at_query: - filter["updated_at__date__gte"] = updated_at_query[0] - else: - filter["updated_at__date__lte"] = updated_at_query[0] + date_filter(filter=filter, date_term="created_at__date", queries=params.get("updated_at", [])) return filter @@ -226,48 +176,10 @@ 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: - match = pattern.match(start_date_query[0]) - if match: - if len(start_date_query) == 3: - digit, term = start_date_query[0].split("_") - date_filter( - filter=filter, - duration=float(digit), - subsequent=start_date_query[1], - term=term, - date_filter="start_date", - offset=start_date_query[2], - ) - else: - if "after" in start_date_query: - filter["start_date__gte"] = start_date_query[0] - else: - filter["start_date__lte"] = start_date_query[0] + date_filter(filter=filter, date_term="start_date", queries=start_dates) else: if params.get("start_date", None) and len(params.get("start_date")): - for query in params.get("start_date"): - start_date_query = query.split(";") - if len(start_date_query) == 2: - match = pattern.match(start_date_query[0]) - if match: - if len(start_date_query) == 3: - digit, term = start_date_query[0].split("_") - date_filter( - filter=filter, - duration=float(digit), - subsequent=start_date_query[1], - term=term, - date_filter="start_date", - offset=start_date_query[2], - ) - else: - if "after" in start_date_query: - filter["start_date__gte"] = start_date_query[0] - else: - filter["start_date__lte"] = start_date_query[0] + date_filter(filter=filter, date_term="start_date", queries=params.get("start_date", None)) return filter @@ -275,49 +187,10 @@ 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: - match = pattern.match(target_date_query[0]) - if match: - if len(target_date_query) == 3: - digit, term = target_date_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=target_date_query[1], - term=term, - date_filter="target_date", - offset=target_date_query[2], - ) - else: - if "after" in target_date_query: - filter["target_date__gt"] = target_date_query[0] - else: - filter["target_date__lt"] = target_date_query[0] + date_filter(filter=filter, date_term="target_date", queries=target_dates) else: if params.get("target_date", None) and len(params.get("target_date")): - for query in params.get("target_date"): - target_date_query = query.split(";") - if len(target_date_query) == 2: - match = pattern.match(target_date_query[0]) - if match: - if len(target_date_query) == 3: - digit, term = target_date_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=target_date_query[1], - term=term, - date_filter="target_date", - offset=target_date_query[2], - ) - else: - if "after" in target_date_query: - filter["target_date__gt"] = target_date_query[0] - else: - filter["target_date__lt"] = target_date_query[0] - + date_filter(filter=filter, date_term="target_date", queries=params.get("target_date", [])) return filter @@ -325,47 +198,10 @@ 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: - match = pattern.match(completed_at_query[0]) - if match: - if len(completed_at_query) == 3: - digit, term = completed_at_query[0].split("_") - date_filter( - filter=filter, - duration=digit, - subsequent=completed_at_query[1], - term=term, - date_filter="completed_at__date", - offset=completed_at_query[2], - ) - else: - if "after" in completed_at_query: - filter["completed_at__date__gte"] = completed_at_query[0] - else: - filter["completed_at__date__lte"] = completed_at_query[0] + date_filter(filter=filter, date_term="completed_at__date", queries=completed_ats) else: if params.get("completed_at", None) and len(params.get("completed_at")): - for query in params.get("completed_at"): - completed_at_query = query.split(";") - if len(completed_at_query) == 2: - match = pattern.match(completed_at_query[0]) - if match: - digit, term = match.group(1), match.group(2) - date_filter( - filter=filter, - duration=digit, - subsequent=completed_at_query[1], - term=term, - date_filter="completed_at__date", - offset=completed_at_query[2], - ) - else: - if "after" in completed_at_query: - filter["completed_at__date__gte"] = completed_at_query[0] - else: - filter["completed_at__date__lte"] = completed_at_query[0] + date_filter(filter=filter, date_term="completed_at__date", queries=params.get("completed_at", [])) return filter