dev: issue list endpoint with issue array

This commit is contained in:
pablohashescobar 2024-02-16 16:37:52 +05:30
parent 5b09083f93
commit fe5c301fc9
4 changed files with 89 additions and 23 deletions

View File

@ -21,10 +21,16 @@ from plane.app.views import (
IssueArchiveViewSet,
IssueRelationViewSet,
IssueDraftViewSet,
IssueListEndpoint,
)
urlpatterns = [
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/list/",
IssueListEndpoint.as_view(),
name="project-issue",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
IssueViewSet.as_view(

View File

@ -85,6 +85,7 @@ from .issue import (
IssueReactionViewSet,
IssueRelationViewSet,
IssueDraftViewSet,
IssueListEndpoint,
)
from .auth_extended import (

View File

@ -83,6 +83,7 @@ from plane.utils.issue_filters import issue_filters
from collections import defaultdict
from plane.utils.cache import cache_path_response, invalidate_path_cache
class IssueViewSet(WebhookMixin, BaseViewSet):
def get_serializer_class(self):
return (
@ -1085,7 +1086,7 @@ class IssueArchiveViewSet(BaseViewSet):
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
@ -1133,10 +1134,7 @@ class IssueArchiveViewSet(BaseViewSet):
order_by_param = request.GET.get("order_by", "-created_at")
issue_queryset = (
self.get_queryset()
.filter(**filters)
)
issue_queryset = self.get_queryset().filter(**filters)
# Priority Ordering
if order_by_param == "priority" or order_by_param == "-priority":
@ -1218,7 +1216,9 @@ class IssueArchiveViewSet(BaseViewSet):
)
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
@invalidate_path_cache("/api/workspaces/:slug/projects/:project_id/archived-issues/", True)
@invalidate_path_cache(
"/api/workspaces/:slug/projects/:project_id/archived-issues/", True
)
def unarchive(self, request, slug, project_id, pk=None):
issue = Issue.objects.get(
workspace__slug=slug,
@ -1582,15 +1582,17 @@ class IssueRelationViewSet(BaseViewSet):
issue_relation = IssueRelation.objects.bulk_create(
[
IssueRelation(
issue_id=issue
if relation_type == "blocking"
else issue_id,
related_issue_id=issue_id
if relation_type == "blocking"
else issue,
relation_type="blocked_by"
if relation_type == "blocking"
else relation_type,
issue_id=(
issue if relation_type == "blocking" else issue_id
),
related_issue_id=(
issue_id if relation_type == "blocking" else issue
),
relation_type=(
"blocked_by"
if relation_type == "blocking"
else relation_type
),
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
@ -1671,9 +1673,7 @@ class IssueDraftViewSet(BaseViewSet):
def get_queryset(self):
return (
Issue.objects.filter(
project_id=self.kwargs.get("project_id")
)
Issue.objects.filter(project_id=self.kwargs.get("project_id"))
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(is_draft=True)
.select_related("workspace", "project", "state", "parent")
@ -1730,10 +1730,7 @@ class IssueDraftViewSet(BaseViewSet):
order_by_param = request.GET.get("order_by", "-created_at")
issue_queryset = (
self.get_queryset()
.filter(**filters)
)
issue_queryset = self.get_queryset().filter(**filters)
# Priority Ordering
if order_by_param == "priority" or order_by_param == "-priority":
@ -1832,7 +1829,9 @@ class IssueDraftViewSet(BaseViewSet):
issue = (
self.get_queryset().filter(pk=serializer.data["id"]).first()
)
return Response(IssueSerializer(issue).data, status=status.HTTP_201_CREATED)
return Response(
IssueSerializer(issue).data, status=status.HTTP_201_CREATED
)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def partial_update(self, request, slug, project_id, pk):
@ -1896,3 +1895,58 @@ class IssueDraftViewSet(BaseViewSet):
origin=request.META.get("HTTP_ORIGIN"),
)
return Response(status=status.HTTP_204_NO_CONTENT)
class IssueListEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def post(self, request, slug, project_id):
issues = request.data.get("issues", [])
if issues:
return Response(
{"error": "Issues are required"},
status=status.HTTP_400_BAD_REQUEST,
)
queryset = (
Issue.issue_objects.filter(
workspace__slug=slug, project_id=project_id, pk__in=issues
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.prefetch_related(
Prefetch(
"issue_reactions",
queryset=IssueReaction.objects.select_related("actor"),
)
)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
sub_issues_count=Issue.issue_objects.filter(
parent=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
).distinct()
serializer = IssueSerializer(queryset)
return Response(serializer.data, status=status.HTTP_200_OK)

View File

@ -15,6 +15,7 @@ def generate_cache_key(custom_path, auth_header=None):
return hashlib.md5(force_bytes(key_data)).hexdigest()
def cache_user_response(timeout, path=None):
"""decorator to create cache per user"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):
@ -36,6 +37,7 @@ def cache_user_response(timeout, path=None):
return decorator
def invalidate_user_cache(path):
"""invalidate cache per user"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):
@ -52,6 +54,7 @@ def invalidate_user_cache(path):
def cache_path_response(timeout, path=None):
"""Cache path responses"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):
@ -72,7 +75,9 @@ def cache_path_response(timeout, path=None):
return _wrapped_view
return decorator
def invalidate_path_cache(path=None, include_url_params=False):
"""invalidate path cache responses"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(instance, request, *args, **kwargs):