Merge branch 'chore/api_endpoints' of github.com:makeplane/plane into chore/api_endpoints

This commit is contained in:
NarayanBavisetti 2023-11-21 19:15:02 +05:30
commit 33ab17e024
10 changed files with 132 additions and 57 deletions

View File

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

View File

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

View File

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

View File

@ -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):

View File

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

View File

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

View File

@ -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
): ):

View File

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

View File

@ -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}
) )

View File

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