forked from github/plane
feat: issues v2 endpoint (#2713)
* feat: issue v2 listing endpoint * dev: issues v3 endpoint * dev: add permission in the grouped endpoint * dev: update grouped endpoint
This commit is contained in:
parent
630e21b954
commit
446981422e
@ -5,7 +5,7 @@ from django.utils import timezone
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from .base import BaseSerializer
|
from .base import BaseSerializer, DynamicBaseSerializer
|
||||||
from .user import UserLiteSerializer
|
from .user import UserLiteSerializer
|
||||||
from .state import StateSerializer, StateLiteSerializer
|
from .state import StateSerializer, StateLiteSerializer
|
||||||
from .project import ProjectLiteSerializer
|
from .project import ProjectLiteSerializer
|
||||||
@ -548,7 +548,7 @@ class IssueSerializer(BaseSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class IssueLiteSerializer(BaseSerializer):
|
class IssueLiteSerializer(DynamicBaseSerializer):
|
||||||
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
|
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
|
||||||
project_detail = ProjectLiteSerializer(read_only=True, source="project")
|
project_detail = ProjectLiteSerializer(read_only=True, source="project")
|
||||||
state_detail = StateLiteSerializer(read_only=True, source="state")
|
state_detail = StateLiteSerializer(read_only=True, source="state")
|
||||||
|
@ -3,6 +3,8 @@ from django.urls import path
|
|||||||
|
|
||||||
from plane.api.views import (
|
from plane.api.views import (
|
||||||
IssueViewSet,
|
IssueViewSet,
|
||||||
|
IssueListEndpoint,
|
||||||
|
IssueListGroupedEndpoint,
|
||||||
LabelViewSet,
|
LabelViewSet,
|
||||||
BulkCreateIssueLabelsEndpoint,
|
BulkCreateIssueLabelsEndpoint,
|
||||||
BulkDeleteIssuesEndpoint,
|
BulkDeleteIssuesEndpoint,
|
||||||
@ -35,6 +37,16 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
name="project-issue",
|
name="project-issue",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"v2/workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
|
||||||
|
IssueListEndpoint.as_view(),
|
||||||
|
name="project-issue",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"v3/workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
|
||||||
|
IssueListGroupedEndpoint.as_view(),
|
||||||
|
name="project-issue",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:pk>/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/<uuid:pk>/",
|
||||||
IssueViewSet.as_view(
|
IssueViewSet.as_view(
|
||||||
|
@ -54,7 +54,12 @@ from .workspace import (
|
|||||||
LeaveWorkspaceEndpoint,
|
LeaveWorkspaceEndpoint,
|
||||||
)
|
)
|
||||||
from .state import StateViewSet
|
from .state import StateViewSet
|
||||||
from .view import GlobalViewViewSet, GlobalViewIssuesViewSet, IssueViewViewSet, IssueViewFavoriteViewSet
|
from .view import (
|
||||||
|
GlobalViewViewSet,
|
||||||
|
GlobalViewIssuesViewSet,
|
||||||
|
IssueViewViewSet,
|
||||||
|
IssueViewFavoriteViewSet,
|
||||||
|
)
|
||||||
from .cycle import (
|
from .cycle import (
|
||||||
CycleViewSet,
|
CycleViewSet,
|
||||||
CycleIssueViewSet,
|
CycleIssueViewSet,
|
||||||
@ -65,6 +70,8 @@ from .cycle import (
|
|||||||
from .asset import FileAssetEndpoint, UserAssetsEndpoint
|
from .asset import FileAssetEndpoint, UserAssetsEndpoint
|
||||||
from .issue import (
|
from .issue import (
|
||||||
IssueViewSet,
|
IssueViewSet,
|
||||||
|
IssueListEndpoint,
|
||||||
|
IssueListGroupedEndpoint,
|
||||||
WorkSpaceIssuesEndpoint,
|
WorkSpaceIssuesEndpoint,
|
||||||
IssueActivityEndpoint,
|
IssueActivityEndpoint,
|
||||||
IssueCommentViewSet,
|
IssueCommentViewSet,
|
||||||
@ -162,7 +169,11 @@ from .analytic import (
|
|||||||
DefaultAnalyticsEndpoint,
|
DefaultAnalyticsEndpoint,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .notification import NotificationViewSet, UnreadNotificationEndpoint, MarkAllReadNotificationViewSet
|
from .notification import (
|
||||||
|
NotificationViewSet,
|
||||||
|
UnreadNotificationEndpoint,
|
||||||
|
MarkAllReadNotificationViewSet,
|
||||||
|
)
|
||||||
|
|
||||||
from .exporter import ExportIssuesEndpoint
|
from .exporter import ExportIssuesEndpoint
|
||||||
|
|
||||||
|
@ -312,6 +312,104 @@ class IssueViewSet(BaseViewSet):
|
|||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
class IssueListEndpoint(BaseAPIView):
|
||||||
|
permission_classes = [
|
||||||
|
ProjectEntityPermission,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get(self, request, slug, project_id):
|
||||||
|
fields = [field for field in request.GET.get("fields", "").split(",") if field]
|
||||||
|
filters = issue_filters(request.query_params, "GET")
|
||||||
|
|
||||||
|
issue_queryset = (
|
||||||
|
Issue.objects.filter(workspace__slug=slug, project_id=project_id)
|
||||||
|
.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"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(**filters)
|
||||||
|
.annotate(cycle_id=F("issue_cycle__cycle_id"))
|
||||||
|
.annotate(module_id=F("issue_module__module_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")
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer = IssueLiteSerializer(
|
||||||
|
issue_queryset, many=True, fields=fields if fields else None
|
||||||
|
)
|
||||||
|
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class IssueListGroupedEndpoint(BaseAPIView):
|
||||||
|
|
||||||
|
permission_classes = [
|
||||||
|
ProjectEntityPermission,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get(self, request, slug, project_id):
|
||||||
|
filters = issue_filters(request.query_params, "GET")
|
||||||
|
fields = [field for field in request.GET.get("fields", "").split(",") if field]
|
||||||
|
|
||||||
|
issue_queryset = (
|
||||||
|
Issue.objects.filter(workspace__slug=slug, project_id=project_id)
|
||||||
|
.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"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.filter(**filters)
|
||||||
|
.annotate(cycle_id=F("issue_cycle__cycle_id"))
|
||||||
|
.annotate(module_id=F("issue_module__module_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")
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
|
||||||
|
issues = IssueLiteSerializer(issue_queryset, many=True, fields=fields if fields else None).data
|
||||||
|
issue_dict = {str(issue["id"]): issue for issue in issues}
|
||||||
|
return Response(
|
||||||
|
issue_dict,
|
||||||
|
status=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserWorkSpaceIssues(BaseAPIView):
|
class UserWorkSpaceIssues(BaseAPIView):
|
||||||
@method_decorator(gzip_page)
|
@method_decorator(gzip_page)
|
||||||
def get(self, request, slug):
|
def get(self, request, slug):
|
||||||
|
Loading…
Reference in New Issue
Block a user