forked from github/plane
feat: global search endpoint for workspace (#529)
This commit is contained in:
parent
a3a792741f
commit
578d724e41
@ -128,6 +128,9 @@ from plane.api.views import (
|
|||||||
ImportServiceEndpoint,
|
ImportServiceEndpoint,
|
||||||
UpdateServiceImportStatusEndpoint,
|
UpdateServiceImportStatusEndpoint,
|
||||||
## End importer
|
## End importer
|
||||||
|
# Search
|
||||||
|
GlobalSearchEndpoint,
|
||||||
|
## End Search
|
||||||
# Gpt
|
# Gpt
|
||||||
GPTIntegrationEndpoint,
|
GPTIntegrationEndpoint,
|
||||||
## End Gpt
|
## End Gpt
|
||||||
@ -1147,6 +1150,13 @@ urlpatterns = [
|
|||||||
name="importer",
|
name="importer",
|
||||||
),
|
),
|
||||||
## End Importer
|
## End Importer
|
||||||
|
# Search
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/search/",
|
||||||
|
GlobalSearchEndpoint.as_view(),
|
||||||
|
name="global-search",
|
||||||
|
),
|
||||||
|
## End Search
|
||||||
# Gpt
|
# Gpt
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/ai-assistant/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/ai-assistant/",
|
||||||
|
@ -122,5 +122,7 @@ from .page import (
|
|||||||
CreatedbyOtherPagesEndpoint,
|
CreatedbyOtherPagesEndpoint,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .search import GlobalSearchEndpoint
|
||||||
|
|
||||||
|
|
||||||
from .gpt import GPTIntegrationEndpoint
|
from .gpt import GPTIntegrationEndpoint
|
||||||
|
162
apiserver/plane/api/views/search.py
Normal file
162
apiserver/plane/api/views/search.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Django imports
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
# Third party imports
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from sentry_sdk import capture_exception
|
||||||
|
|
||||||
|
# Module imports
|
||||||
|
from .base import BaseAPIView
|
||||||
|
from plane.db.models import Workspace, Project, Issue, Cycle, Module, Page, IssueView
|
||||||
|
|
||||||
|
|
||||||
|
class GlobalSearchEndpoint(BaseAPIView):
|
||||||
|
"""Endpoint to search across multiple fields in the workspace and
|
||||||
|
also show related workspace if found
|
||||||
|
"""
|
||||||
|
|
||||||
|
def filter_workspaces(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Workspace.objects.filter(
|
||||||
|
q, workspace_member__member=self.request.user
|
||||||
|
).values("name", "id", "slug")
|
||||||
|
|
||||||
|
def filter_projects(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Project.objects.filter(
|
||||||
|
q,
|
||||||
|
Q(project_projectmember__member=self.request.user) | Q(network=2),
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values("name", "id", "identifier", "workspace__slug")
|
||||||
|
|
||||||
|
def filter_issues(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Issue.objects.filter(
|
||||||
|
q,
|
||||||
|
project__project_projectmember__member=self.request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values(
|
||||||
|
"name",
|
||||||
|
"id",
|
||||||
|
"sequence_id",
|
||||||
|
"project__identifier",
|
||||||
|
"project_id",
|
||||||
|
"workspace__slug",
|
||||||
|
)
|
||||||
|
|
||||||
|
def filter_cycles(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Cycle.objects.filter(
|
||||||
|
q,
|
||||||
|
project__project_projectmember__member=self.request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values(
|
||||||
|
"name",
|
||||||
|
"id",
|
||||||
|
"project_id",
|
||||||
|
"workspace__slug",
|
||||||
|
)
|
||||||
|
|
||||||
|
def filter_modules(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Module.objects.filter(
|
||||||
|
q,
|
||||||
|
project__project_projectmember__member=self.request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values(
|
||||||
|
"name",
|
||||||
|
"id",
|
||||||
|
"project_id",
|
||||||
|
"workspace__slug",
|
||||||
|
)
|
||||||
|
|
||||||
|
def filter_pages(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return Page.objects.filter(
|
||||||
|
q,
|
||||||
|
project__project_projectmember__member=self.request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values(
|
||||||
|
"name",
|
||||||
|
"id",
|
||||||
|
"project_id",
|
||||||
|
"workspace__slug",
|
||||||
|
)
|
||||||
|
|
||||||
|
def filter_views(self, query, slug):
|
||||||
|
fields = ["name"]
|
||||||
|
q = Q()
|
||||||
|
for field in fields:
|
||||||
|
q |= Q(**{f"{field}__icontains": query})
|
||||||
|
return IssueView.objects.filter(
|
||||||
|
q,
|
||||||
|
project__project_projectmember__member=self.request.user,
|
||||||
|
workspace__slug=slug,
|
||||||
|
).values(
|
||||||
|
"name",
|
||||||
|
"id",
|
||||||
|
"project_id",
|
||||||
|
"workspace__slug",
|
||||||
|
)
|
||||||
|
|
||||||
|
def get(self, request, slug):
|
||||||
|
try:
|
||||||
|
query = request.query_params.get("search", False)
|
||||||
|
if not query:
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"results": {
|
||||||
|
"workspace": [],
|
||||||
|
"project": [],
|
||||||
|
"issue": [],
|
||||||
|
"cycle": [],
|
||||||
|
"module": [],
|
||||||
|
"issue_view": [],
|
||||||
|
"page": [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
status=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
MODELS_MAPPER = {
|
||||||
|
"workspace": self.filter_workspaces,
|
||||||
|
"project": self.filter_projects,
|
||||||
|
"issue": self.filter_issues,
|
||||||
|
"cycle": self.filter_cycles,
|
||||||
|
"module": self.filter_modules,
|
||||||
|
"issue_view": self.filter_views,
|
||||||
|
"page": self.filter_pages,
|
||||||
|
}
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for model in MODELS_MAPPER.keys():
|
||||||
|
func = MODELS_MAPPER.get(model, None)
|
||||||
|
results[model] = func(query, slug)
|
||||||
|
return Response({"results": results}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
capture_exception(e)
|
||||||
|
return Response(
|
||||||
|
{"error": "Something went wrong please try again later"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user