forked from github/plane
Merge branch 'chore/api_endpoints' of github.com:makeplane/plane into chore/api_endpoints
This commit is contained in:
commit
33ab17e024
@ -8,6 +8,12 @@ class InboxIssueSerializer(BaseSerializer):
|
|||||||
model = InboxIssue
|
model = InboxIssue
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"project",
|
"id",
|
||||||
"workspace",
|
"workspace",
|
||||||
|
"project",
|
||||||
|
"issue",
|
||||||
|
"created_by",
|
||||||
|
"updated_by",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
]
|
]
|
@ -42,6 +42,7 @@ class IssueSerializer(BaseSerializer):
|
|||||||
model = Issue
|
model = Issue
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
"workspace",
|
"workspace",
|
||||||
"project",
|
"project",
|
||||||
"created_by",
|
"created_by",
|
||||||
@ -65,6 +66,7 @@ class IssueSerializer(BaseSerializer):
|
|||||||
project_id=self.context.get("project_id"),
|
project_id=self.context.get("project_id"),
|
||||||
is_active=True,
|
is_active=True,
|
||||||
member_id__in=data["assignees"],
|
member_id__in=data["assignees"],
|
||||||
|
is_active=True,
|
||||||
).values_list("member_id", flat=True)
|
).values_list("member_id", flat=True)
|
||||||
|
|
||||||
# Validate labels are from project
|
# Validate labels are from project
|
||||||
@ -232,8 +234,13 @@ class LabelSerializer(BaseSerializer):
|
|||||||
model = Label
|
model = Label
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
"workspace",
|
"workspace",
|
||||||
"project",
|
"project",
|
||||||
|
"created_by",
|
||||||
|
"updated_by",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -242,13 +249,14 @@ class IssueLinkSerializer(BaseSerializer):
|
|||||||
model = IssueLink
|
model = IssueLink
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
"workspace",
|
"workspace",
|
||||||
"project",
|
"project",
|
||||||
|
"issue",
|
||||||
"created_by",
|
"created_by",
|
||||||
"updated_by",
|
"updated_by",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"issue",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Validation if url already exists
|
# Validation if url already exists
|
||||||
@ -267,13 +275,14 @@ class IssueAttachmentSerializer(BaseSerializer):
|
|||||||
model = IssueAttachment
|
model = IssueAttachment
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
|
"workspace",
|
||||||
|
"project",
|
||||||
|
"issue",
|
||||||
"created_by",
|
"created_by",
|
||||||
"updated_by",
|
"updated_by",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"workspace",
|
|
||||||
"project",
|
|
||||||
"issue",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -283,37 +292,21 @@ class IssueCommentSerializer(BaseSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = IssueComment
|
model = IssueComment
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
|
||||||
"workspace",
|
|
||||||
"project",
|
|
||||||
"issue",
|
|
||||||
"created_by",
|
|
||||||
"updated_by",
|
|
||||||
"created_at",
|
|
||||||
"updated_at",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class IssueAttachmentSerializer(BaseSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = IssueAttachment
|
|
||||||
fields = "__all__"
|
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"id",
|
"id",
|
||||||
|
"workspace",
|
||||||
|
"project",
|
||||||
|
"issue",
|
||||||
"created_by",
|
"created_by",
|
||||||
"updated_by",
|
"updated_by",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"workspace",
|
|
||||||
"project",
|
|
||||||
"issue",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class IssueActivitySerializer(BaseSerializer):
|
class IssueActivitySerializer(BaseSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IssueActivity
|
model = IssueActivity
|
||||||
fields = "__all__"
|
|
||||||
exclude = [
|
exclude = [
|
||||||
"created_by",
|
"created_by",
|
||||||
"udpated_by",
|
"udpated_by",
|
||||||
|
@ -33,6 +33,7 @@ class ModuleSerializer(BaseSerializer):
|
|||||||
model = Module
|
model = Module
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
"workspace",
|
"workspace",
|
||||||
"project",
|
"project",
|
||||||
"created_by",
|
"created_by",
|
||||||
|
@ -20,8 +20,12 @@ class ProjectSerializer(BaseSerializer):
|
|||||||
model = Project
|
model = Project
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"workspace",
|
|
||||||
"id",
|
"id",
|
||||||
|
"workspace",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"created_by",
|
||||||
|
"updated_by",
|
||||||
]
|
]
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
|
@ -5,12 +5,12 @@ from plane.api.views import InboxIssueAPIEndpoint
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/inboxes/<uuid:inbox_id>/inbox-issues/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/inbox-issues/",
|
||||||
InboxIssueAPIEndpoint.as_view(),
|
InboxIssueAPIEndpoint.as_view(),
|
||||||
name="inbox-issue",
|
name="inbox-issue",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/inboxes/<uuid:inbox_id>/inbox-issues/<uuid:pk>/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/inbox-issues/<uuid:pk>/",
|
||||||
InboxIssueAPIEndpoint.as_view(),
|
InboxIssueAPIEndpoint.as_view(),
|
||||||
name="inbox-issue",
|
name="inbox-issue",
|
||||||
),
|
),
|
||||||
|
@ -17,7 +17,6 @@ from plane.app.permissions import ProjectEntityPermission
|
|||||||
from plane.api.serializers import (
|
from plane.api.serializers import (
|
||||||
CycleSerializer,
|
CycleSerializer,
|
||||||
CycleIssueSerializer,
|
CycleIssueSerializer,
|
||||||
IssueSerializer,
|
|
||||||
)
|
)
|
||||||
from plane.bgtasks.issue_activites_task import issue_activity
|
from plane.bgtasks.issue_activites_task import issue_activity
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from rest_framework.response import Response
|
|||||||
from .base import BaseAPIView
|
from .base import BaseAPIView
|
||||||
from plane.app.permissions import ProjectLitePermission
|
from plane.app.permissions import ProjectLitePermission
|
||||||
from plane.api.serializers import InboxIssueSerializer, IssueSerializer
|
from plane.api.serializers import InboxIssueSerializer, IssueSerializer
|
||||||
from plane.db.models import InboxIssue, Issue, State, ProjectMember
|
from plane.db.models import InboxIssue, Issue, State, ProjectMember, Project, Inbox
|
||||||
from plane.bgtasks.issue_activites_task import issue_activity
|
from plane.bgtasks.issue_activites_task import issue_activity
|
||||||
|
|
||||||
|
|
||||||
@ -37,29 +37,39 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.filter_queryset(
|
inbox = Inbox.objects.filter(
|
||||||
super()
|
workspace__slug=self.kwargs.get("slug"),
|
||||||
.get_queryset()
|
project_id=self.kwargs.get("project_id"),
|
||||||
.filter(
|
).first()
|
||||||
|
|
||||||
|
project = Project.objects.get(
|
||||||
|
workspace__slug=self.kwargs.get("slug"), pk=self.kwargs.get("project_id")
|
||||||
|
)
|
||||||
|
|
||||||
|
if inbox is None and not project.inbox_view:
|
||||||
|
return InboxIssue.objects.none()
|
||||||
|
|
||||||
|
return (
|
||||||
|
InboxIssue.objects.filter(
|
||||||
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
|
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
|
||||||
workspace__slug=self.kwargs.get("slug"),
|
workspace__slug=self.kwargs.get("slug"),
|
||||||
project_id=self.kwargs.get("project_id"),
|
project_id=self.kwargs.get("project_id"),
|
||||||
inbox_id=self.kwargs.get("inbox_id"),
|
inbox_id=inbox.id,
|
||||||
)
|
)
|
||||||
.select_related("issue", "workspace", "project")
|
.select_related("issue", "workspace", "project")
|
||||||
.order_by(self.kwargs.get("order_by", "-created_at"))
|
.order_by(self.kwargs.get("order_by", "-created_at"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, request, slug, project_id, inbox_id, pk=None):
|
def get(self, request, slug, project_id, pk=None):
|
||||||
if pk:
|
if pk:
|
||||||
issue_queryset = self.get_queryset().get(pk=pk)
|
inbox_issue_queryset = self.get_queryset().get(pk=pk)
|
||||||
issues_data = InboxIssueSerializer(
|
inbox_issue_data = InboxIssueSerializer(
|
||||||
issue_queryset,
|
inbox_issue_queryset,
|
||||||
fields=self.fields,
|
fields=self.fields,
|
||||||
expand=self.expand,
|
expand=self.expand,
|
||||||
).data
|
).data
|
||||||
return Response(
|
return Response(
|
||||||
issues_data,
|
inbox_issue_data,
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
issue_queryset = self.get_queryset()
|
issue_queryset = self.get_queryset()
|
||||||
@ -74,12 +84,30 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
).data,
|
).data,
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(self, request, slug, project_id, inbox_id):
|
def post(self, request, slug, project_id):
|
||||||
if not request.data.get("issue", {}).get("name", False):
|
if not request.data.get("issue", {}).get("name", False):
|
||||||
return Response(
|
return Response(
|
||||||
{"error": "Name is required"}, status=status.HTTP_400_BAD_REQUEST
|
{"error": "Name is required"}, status=status.HTTP_400_BAD_REQUEST
|
||||||
)
|
)
|
||||||
|
|
||||||
|
inbox = Inbox.objects.filter(
|
||||||
|
workspace__slug=slug, project_id=project_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
project = Project.objects.get(
|
||||||
|
workspace__slug=slug,
|
||||||
|
pk=project_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Inbox view
|
||||||
|
if inbox is None and not project.inbox_view:
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"error": "Inbox is not enabled for this project enable it through the project settings"
|
||||||
|
},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
# Check for valid priority
|
# Check for valid priority
|
||||||
if not request.data.get("issue", {}).get("priority", "none") in [
|
if not request.data.get("issue", {}).get("priority", "none") in [
|
||||||
"low",
|
"low",
|
||||||
@ -123,21 +151,45 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
current_instance=None,
|
current_instance=None,
|
||||||
epoch=int(timezone.now().timestamp()),
|
epoch=int(timezone.now().timestamp()),
|
||||||
)
|
)
|
||||||
|
|
||||||
# create an inbox issue
|
# create an inbox issue
|
||||||
InboxIssue.objects.create(
|
inbox_issue = InboxIssue.objects.create(
|
||||||
inbox_id=inbox_id,
|
inbox_id=inbox.id,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
issue=issue,
|
issue=issue,
|
||||||
source=request.data.get("source", "in-app"),
|
source=request.data.get("source", "in-app"),
|
||||||
)
|
)
|
||||||
|
|
||||||
serializer = IssueSerializer(issue)
|
serializer = InboxIssueSerializer(inbox_issue)
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
def patch(self, request, slug, project_id, inbox_id, pk):
|
def patch(self, request, slug, project_id, pk):
|
||||||
inbox_issue = InboxIssue.objects.get(
|
inbox = Inbox.objects.filter(
|
||||||
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
|
workspace__slug=slug, project_id=project_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
project = Project.objects.get(
|
||||||
|
workspace__slug=slug,
|
||||||
|
pk=project_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Inbox view
|
||||||
|
if inbox is None and not project.inbox_view:
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"error": "Inbox is not enabled for this project enable it through the project settings"
|
||||||
|
},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get the inbox issue
|
||||||
|
inbox_issue = InboxIssue.objects.get(
|
||||||
|
pk=pk,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
inbox_id=inbox.id,
|
||||||
|
)
|
||||||
|
|
||||||
# Get the project member
|
# Get the project member
|
||||||
project_member = ProjectMember.objects.get(
|
project_member = ProjectMember.objects.get(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
@ -145,6 +197,7 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
member=request.user,
|
member=request.user,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only project members admins and created_by users can access this endpoint
|
# Only project members admins and created_by users can access this endpoint
|
||||||
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
|
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
|
||||||
request.user.id
|
request.user.id
|
||||||
@ -244,10 +297,33 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK
|
InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(self, request, slug, project_id, inbox_id, pk):
|
def delete(self, request, slug, project_id, pk):
|
||||||
inbox_issue = InboxIssue.objects.get(
|
inbox = Inbox.objects.filter(
|
||||||
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
|
workspace__slug=slug, project_id=project_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
project = Project.objects.get(
|
||||||
|
workspace__slug=slug,
|
||||||
|
pk=project_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Inbox view
|
||||||
|
if inbox is None and not project.inbox_view:
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"error": "Inbox is not enabled for this project enable it through the project settings"
|
||||||
|
},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get the inbox issue
|
||||||
|
inbox_issue = InboxIssue.objects.get(
|
||||||
|
pk=pk,
|
||||||
|
workspace__slug=slug,
|
||||||
|
project_id=project_id,
|
||||||
|
inbox_id=inbox.id,
|
||||||
|
)
|
||||||
|
|
||||||
# Get the project member
|
# Get the project member
|
||||||
project_member = ProjectMember.objects.get(
|
project_member = ProjectMember.objects.get(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
@ -256,6 +332,7 @@ class InboxIssueAPIEndpoint(BaseAPIView):
|
|||||||
is_active=True,
|
is_active=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check the inbox issue created
|
||||||
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
|
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
|
||||||
request.user.id
|
request.user.id
|
||||||
):
|
):
|
||||||
|
@ -22,7 +22,6 @@ from django.utils import timezone
|
|||||||
# Third party imports
|
# Third party imports
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.parsers import MultiPartParser, FormParser
|
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from .base import BaseAPIView, WebhookMixin
|
from .base import BaseAPIView, WebhookMixin
|
||||||
@ -48,7 +47,6 @@ from plane.api.serializers import (
|
|||||||
LabelSerializer,
|
LabelSerializer,
|
||||||
IssueLinkSerializer,
|
IssueLinkSerializer,
|
||||||
IssueCommentSerializer,
|
IssueCommentSerializer,
|
||||||
IssueAttachmentSerializer,
|
|
||||||
IssueActivitySerializer,
|
IssueActivitySerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -103,7 +101,6 @@ class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
|||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
)
|
)
|
||||||
|
|
||||||
filters = issue_filters(request.query_params, "GET")
|
|
||||||
# Custom ordering for priority and state
|
# Custom ordering for priority and state
|
||||||
priority_order = ["urgent", "high", "medium", "low", "none"]
|
priority_order = ["urgent", "high", "medium", "low", "none"]
|
||||||
state_order = ["backlog", "unstarted", "started", "completed", "cancelled"]
|
state_order = ["backlog", "unstarted", "started", "completed", "cancelled"]
|
||||||
@ -112,7 +109,6 @@ class IssueAPIEndpoint(WebhookMixin, BaseAPIView):
|
|||||||
|
|
||||||
issue_queryset = (
|
issue_queryset = (
|
||||||
self.get_queryset()
|
self.get_queryset()
|
||||||
.filter(**filters)
|
|
||||||
.annotate(cycle_id=F("issue_cycle__cycle_id"))
|
.annotate(cycle_id=F("issue_cycle__cycle_id"))
|
||||||
.annotate(module_id=F("issue_module__module_id"))
|
.annotate(module_id=F("issue_module__module_id"))
|
||||||
.annotate(
|
.annotate(
|
||||||
|
@ -114,7 +114,7 @@ class ProjectAPIEndpoint(WebhookMixin, BaseAPIView):
|
|||||||
).select_related("member"),
|
).select_related("member"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.order_by("sort_order", "name")
|
.order_by(request.GET.get("order_by", "sort_order"))
|
||||||
)
|
)
|
||||||
return self.paginate(
|
return self.paginate(
|
||||||
request=request,
|
request=request,
|
||||||
@ -131,7 +131,6 @@ class ProjectAPIEndpoint(WebhookMixin, BaseAPIView):
|
|||||||
def post(self, request, slug):
|
def post(self, request, slug):
|
||||||
try:
|
try:
|
||||||
workspace = Workspace.objects.get(slug=slug)
|
workspace = Workspace.objects.get(slug=slug)
|
||||||
|
|
||||||
serializer = ProjectSerializer(
|
serializer = ProjectSerializer(
|
||||||
data={**request.data}, context={"workspace_id": workspace.id}
|
data={**request.data}, context={"workspace_id": workspace.id}
|
||||||
)
|
)
|
||||||
|
@ -65,7 +65,7 @@ urlpatterns = [
|
|||||||
name="project-member-invite",
|
name="project-member-invite",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"users/me/invitations/projects/",
|
"users/me/workspaces/<str:slug>/projects/invitations/",
|
||||||
UserProjectInvitationsViewset.as_view(
|
UserProjectInvitationsViewset.as_view(
|
||||||
{
|
{
|
||||||
"get": "list",
|
"get": "list",
|
||||||
|
Loading…
Reference in New Issue
Block a user