forked from github/plane
feat(api/issuesBySequenceId): add api to retrieve issue based on its sequence identitifier (#4170)
This commit is contained in:
parent
d9f11733ad
commit
7f99b9a554
@ -6,9 +6,15 @@ from plane.api.views import (
|
|||||||
IssueLinkAPIEndpoint,
|
IssueLinkAPIEndpoint,
|
||||||
IssueCommentAPIEndpoint,
|
IssueCommentAPIEndpoint,
|
||||||
IssueActivityAPIEndpoint,
|
IssueActivityAPIEndpoint,
|
||||||
|
WorkspaceIssueAPIEndpoint,
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/issues/<str:project__identifier>-<str:issue__identifier>/",
|
||||||
|
WorkspaceIssueAPIEndpoint.as_view(),
|
||||||
|
name="issue-by-identifier",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/issues/",
|
||||||
IssueAPIEndpoint.as_view(),
|
IssueAPIEndpoint.as_view(),
|
||||||
|
@ -3,6 +3,7 @@ from .project import ProjectAPIEndpoint, ProjectArchiveUnarchiveAPIEndpoint
|
|||||||
from .state import StateAPIEndpoint
|
from .state import StateAPIEndpoint
|
||||||
|
|
||||||
from .issue import (
|
from .issue import (
|
||||||
|
WorkspaceIssueAPIEndpoint,
|
||||||
IssueAPIEndpoint,
|
IssueAPIEndpoint,
|
||||||
LabelAPIEndpoint,
|
LabelAPIEndpoint,
|
||||||
IssueLinkAPIEndpoint,
|
IssueLinkAPIEndpoint,
|
||||||
|
@ -32,6 +32,7 @@ from plane.api.serializers import (
|
|||||||
LabelSerializer,
|
LabelSerializer,
|
||||||
)
|
)
|
||||||
from plane.app.permissions import (
|
from plane.app.permissions import (
|
||||||
|
WorkspaceEntityPermission,
|
||||||
ProjectEntityPermission,
|
ProjectEntityPermission,
|
||||||
ProjectLitePermission,
|
ProjectLitePermission,
|
||||||
ProjectMemberPermission,
|
ProjectMemberPermission,
|
||||||
@ -51,6 +52,65 @@ from plane.db.models import (
|
|||||||
from .base import BaseAPIView, WebhookMixin
|
from .base import BaseAPIView, WebhookMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceIssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
||||||
|
"""
|
||||||
|
This viewset provides `retrieveByIssueId` on workspace level
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
model = Issue
|
||||||
|
webhook_event = "issue"
|
||||||
|
permission_classes = [
|
||||||
|
ProjectEntityPermission
|
||||||
|
]
|
||||||
|
serializer_class = IssueSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def project__identifier(self):
|
||||||
|
return self.kwargs.get("project__identifier", None)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return (
|
||||||
|
Issue.issue_objects.annotate(
|
||||||
|
sub_issues_count=Issue.issue_objects.filter(
|
||||||
|
parent=OuterRef("id")
|
||||||
|
)
|
||||||
|
.order_by()
|
||||||
|
.annotate(count=Func(F("id"), function="Count"))
|
||||||
|
.values("count")
|
||||||
|
)
|
||||||
|
.filter(workspace__slug=self.kwargs.get("slug"))
|
||||||
|
.filter(project__identifier=self.kwargs.get("project__identifier"))
|
||||||
|
.select_related("project")
|
||||||
|
.select_related("workspace")
|
||||||
|
.select_related("state")
|
||||||
|
.select_related("parent")
|
||||||
|
.prefetch_related("assignees")
|
||||||
|
.prefetch_related("labels")
|
||||||
|
.order_by(self.kwargs.get("order_by", "-created_at"))
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
def get(self, request, slug, project__identifier=None, issue__identifier=None):
|
||||||
|
if issue__identifier and project__identifier:
|
||||||
|
issue = Issue.issue_objects.annotate(
|
||||||
|
sub_issues_count=Issue.issue_objects.filter(
|
||||||
|
parent=OuterRef("id")
|
||||||
|
)
|
||||||
|
.order_by()
|
||||||
|
.annotate(count=Func(F("id"), function="Count"))
|
||||||
|
.values("count")
|
||||||
|
).get(workspace__slug=slug, project__identifier=project__identifier, sequence_id=issue__identifier)
|
||||||
|
return Response(
|
||||||
|
IssueSerializer(
|
||||||
|
issue,
|
||||||
|
fields=self.fields,
|
||||||
|
expand=self.expand,
|
||||||
|
).data,
|
||||||
|
status=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
|
||||||
class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
||||||
"""
|
"""
|
||||||
This viewset automatically provides `list`, `create`, `retrieve`,
|
This viewset automatically provides `list`, `create`, `retrieve`,
|
||||||
@ -282,7 +342,7 @@ class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
|||||||
)
|
)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
if (
|
if (
|
||||||
str(request.data.get("external_id"))
|
request.data.get("external_id")
|
||||||
and (issue.external_id != str(request.data.get("external_id")))
|
and (issue.external_id != str(request.data.get("external_id")))
|
||||||
and Issue.objects.filter(
|
and Issue.objects.filter(
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
|
@ -79,6 +79,16 @@ class ProjectEntityPermission(BasePermission):
|
|||||||
if request.user.is_anonymous:
|
if request.user.is_anonymous:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Handle requests based on project__identifier
|
||||||
|
if hasattr(view, "project__identifier") and view.project__identifier:
|
||||||
|
if request.method in SAFE_METHODS:
|
||||||
|
return ProjectMember.objects.filter(
|
||||||
|
workspace__slug=view.workspace_slug,
|
||||||
|
member=request.user,
|
||||||
|
project__identifier=view.project__identifier,
|
||||||
|
is_active=True,
|
||||||
|
).exists()
|
||||||
|
|
||||||
## Safe Methods -> Handle the filtering logic in queryset
|
## Safe Methods -> Handle the filtering logic in queryset
|
||||||
if request.method in SAFE_METHODS:
|
if request.method in SAFE_METHODS:
|
||||||
return ProjectMember.objects.filter(
|
return ProjectMember.objects.filter(
|
||||||
|
Loading…
Reference in New Issue
Block a user