feat(api/issuesBySequenceId): add api to retrieve issue based on its sequence identitifier (#4170)

This commit is contained in:
Michael Ermer 2024-04-24 14:12:12 +02:00 committed by GitHub
parent d9f11733ad
commit 7f99b9a554
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 1 deletions

View File

@ -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(),

View File

@ -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,

View File

@ -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,

View File

@ -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(