From 5f8d5ea388a6ee1897247f3e34368aafb61f88e3 Mon Sep 17 00:00:00 2001 From: Sangeetha Date: Mon, 12 May 2025 19:14:10 +0530 Subject: [PATCH] [WEB-4054] chore: search-issues endpoint code refactoring (#7029) * chore: moved some code to seperate function * fix: function name typo --- apiserver/plane/app/views/search/issue.py | 134 ++++++++++++++++------ 1 file changed, 99 insertions(+), 35 deletions(-) diff --git a/apiserver/plane/app/views/search/issue.py b/apiserver/plane/app/views/search/issue.py index 3db9e1cba1..ed826782a7 100644 --- a/apiserver/plane/app/views/search/issue.py +++ b/apiserver/plane/app/views/search/issue.py @@ -1,5 +1,5 @@ # Django imports -from django.db.models import Q +from django.db.models import Q, QuerySet # Third party imports from rest_framework import status @@ -12,6 +12,95 @@ from plane.utils.issue_search import search_issues class IssueSearchEndpoint(BaseAPIView): + def filter_issues_by_project(self, project_id: int, issues: QuerySet) -> QuerySet: + """ + Filter issues by project + """ + + issues = issues.filter(project_id=project_id) + + return issues + + def search_issues_by_query(self, query: str, issues: QuerySet) -> QuerySet: + """ + Search issues by query + """ + + issues = search_issues(query, issues) + + return issues + + def search_issues_and_excluding_parent( + self, issues: QuerySet, issue_id: str + ) -> QuerySet: + """ + Search issues and epics by query excluding the parent + """ + + issue = Issue.issue_objects.filter(pk=issue_id).first() + if issue: + issues = issues.filter( + ~Q(pk=issue_id), ~Q(pk=issue.parent_id), ~Q(parent_id=issue_id) + ) + return issues + + def filter_issues_excluding_related_issues( + self, issue_id: str, issues: QuerySet + ) -> QuerySet: + """ + Filter issues excluding related issues + """ + + issue = Issue.issue_objects.filter(pk=issue_id).first() + related_issue_ids = ( + IssueRelation.objects.filter(Q(related_issue=issue) | Q(issue=issue)) + .values_list("issue_id", "related_issue_id") + .distinct() + ) + + related_issue_ids = [item for sublist in related_issue_ids for item in sublist] + + if issue: + issues = issues.filter(~Q(pk=issue_id), ~Q(pk__in=related_issue_ids)) + + return issues + + def filter_root_issues_only(self, issue_id: str, issues: QuerySet) -> QuerySet: + """ + Filter root issues only + """ + issue = Issue.issue_objects.filter(pk=issue_id).first() + if issue: + issues = issues.filter(~Q(pk=issue_id), parent__isnull=True) + if issue.parent: + issues = issues.filter(~Q(pk=issue.parent_id)) + return issues + + def exclude_issues_in_cycles(self, issues: QuerySet) -> QuerySet: + """ + Exclude issues in cycles + """ + issues = issues.exclude( + Q(issue_cycle__isnull=False) & Q(issue_cycle__deleted_at__isnull=True) + ) + return issues + + def exclude_issues_in_module(self, issues: QuerySet, module: str) -> QuerySet: + """ + Exclude issues in a module + """ + issues = issues.exclude( + Q(issue_module__module=module) & Q(issue_module__deleted_at__isnull=True) + ) + return issues + + def filter_issues_without_target_date(self, issues: QuerySet) -> QuerySet: + """ + Filter issues without a target date + """ + issues = issues.filter(target_date__isnull=True) + return issues + def get(self, request, slug, project_id): query = request.query_params.get("search", False) workspace_search = request.query_params.get("workspace_search", "false") @@ -21,7 +110,6 @@ class IssueSearchEndpoint(BaseAPIView): module = request.query_params.get("module", False) sub_issue = request.query_params.get("sub_issue", "false") target_date = request.query_params.get("target_date", True) - issue_id = request.query_params.get("issue_id", False) issues = Issue.issue_objects.filter( @@ -32,52 +120,28 @@ class IssueSearchEndpoint(BaseAPIView): ) if workspace_search == "false": - issues = issues.filter(project_id=project_id) + issues = self.filter_issues_by_project(project_id, issues) if query: - issues = search_issues(query, issues) + issues = self.search_issues_by_query(query, issues) if parent == "true" and issue_id: - issue = Issue.issue_objects.filter(pk=issue_id).first() - if issue: - issues = issues.filter( - ~Q(pk=issue_id), ~Q(pk=issue.parent_id), ~Q(parent_id=issue_id) - ) + issues = self.search_issues_and_excluding_parent(issues, issue_id) + if issue_relation == "true" and issue_id: - issue = Issue.issue_objects.filter(pk=issue_id).first() - related_issue_ids = IssueRelation.objects.filter( - Q(related_issue=issue) | Q(issue=issue) - ).values_list( - "issue_id", "related_issue_id" - ).distinct() + issues = self.filter_issues_excluding_related_issues(issue_id, issues) - related_issue_ids = [item for sublist in related_issue_ids for item in sublist] - - if issue: - issues = issues.filter( - ~Q(pk=issue_id), - ~Q(pk__in=related_issue_ids), - ) if sub_issue == "true" and issue_id: - issue = Issue.issue_objects.filter(pk=issue_id).first() - if issue: - issues = issues.filter(~Q(pk=issue_id), parent__isnull=True) - if issue.parent: - issues = issues.filter(~Q(pk=issue.parent_id)) + issues = self.filter_root_issues_only(issue_id, issues) if cycle == "true": - issues = issues.exclude( - Q(issue_cycle__isnull=False) & Q(issue_cycle__deleted_at__isnull=True) - ) + issues = self.exclude_issues_in_cycles(issues) if module: - issues = issues.exclude( - Q(issue_module__module=module) - & Q(issue_module__deleted_at__isnull=True) - ) + issues = self.exclude_issues_in_module(issues, module) if target_date == "none": - issues = issues.filter(target_date__isnull=True) + issues = self.filter_issues_without_target_date(issues) if ProjectMember.objects.filter( project_id=project_id, member=self.request.user, is_active=True, role=5