Compare commits

...

5 Commits

Author SHA1 Message Date
NarayanBavisetti
168823e5ba dev: serializer updates for workspace, project, inbox etc. 2023-08-21 14:12:48 +05:30
NarayanBavisetti
ea3b9456f9 Merge branch 'develop' of github.com:makeplane/plane into chore/serializers 2023-08-18 16:05:42 +05:30
NarayanBavisetti
2058334559 fix: created dynamic serializer 2023-08-18 16:04:28 +05:30
NarayanBavisetti
e1b77d400a Merge branch 'develop' of github.com:makeplane/plane into chore/serializers 2023-08-16 17:40:52 +05:30
NarayanBavisetti
77977d7d32 fix: changed the serializers 2023-08-16 12:42:34 +05:30
29 changed files with 1657 additions and 342 deletions

View File

@ -1,13 +1,11 @@
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserSerializer, UserLiteSerializer, ChangePasswordSerializer, ResetPasswordSerializer, UserAdminLiteSerializer from .user import UserSerializer, ChangePasswordSerializer, ResetPasswordSerializer
from .workspace import ( from .workspace import (
WorkSpaceSerializer, WorkSpaceSerializer,
WorkSpaceMemberSerializer, WorkSpaceMemberSerializer,
TeamSerializer, TeamSerializer,
WorkSpaceMemberInviteSerializer, WorkSpaceMemberInviteSerializer,
WorkspaceLiteSerializer,
WorkspaceThemeSerializer, WorkspaceThemeSerializer,
WorkspaceMemberAdminSerializer,
) )
from .project import ( from .project import (
ProjectSerializer, ProjectSerializer,
@ -16,12 +14,11 @@ from .project import (
ProjectMemberInviteSerializer, ProjectMemberInviteSerializer,
ProjectIdentifierSerializer, ProjectIdentifierSerializer,
ProjectFavoriteSerializer, ProjectFavoriteSerializer,
ProjectLiteSerializer,
ProjectMemberLiteSerializer, ProjectMemberLiteSerializer,
ProjectDeployBoardSerializer, ProjectDeployBoardSerializer,
ProjectMemberAdminSerializer, ProjectMemberAdminSerializer,
) )
from .state import StateSerializer, StateLiteSerializer from .state import StateSerializer
from .view import IssueViewSerializer, IssueViewFavoriteSerializer from .view import IssueViewSerializer, IssueViewFavoriteSerializer
from .cycle import CycleSerializer, CycleIssueSerializer, CycleFavoriteSerializer, CycleWriteSerializer from .cycle import CycleSerializer, CycleIssueSerializer, CycleFavoriteSerializer, CycleWriteSerializer
from .asset import FileAssetSerializer from .asset import FileAssetSerializer
@ -32,7 +29,7 @@ from .issue import (
IssuePropertySerializer, IssuePropertySerializer,
BlockerIssueSerializer, BlockerIssueSerializer,
BlockedIssueSerializer, BlockedIssueSerializer,
IssueAssigneeSerializer, # IssueAssigneeSerializer,
LabelSerializer, LabelSerializer,
IssueSerializer, IssueSerializer,
IssueFlatSerializer, IssueFlatSerializer,
@ -73,7 +70,6 @@ from .page import PageSerializer, PageBlockSerializer, PageFavoriteSerializer
from .estimate import ( from .estimate import (
EstimateSerializer, EstimateSerializer,
EstimatePointSerializer, EstimatePointSerializer,
EstimateReadSerializer,
) )
from .inbox import InboxSerializer, InboxIssueSerializer, IssueStateInboxSerializer from .inbox import InboxSerializer, InboxIssueSerializer, IssueStateInboxSerializer

View File

@ -1,5 +1,33 @@
from rest_framework import serializers from rest_framework import serializers
def filterFields(self, fields):
for field_name in fields:
if isinstance(field_name, dict):
for key, value in field_name.items():
if isinstance(value, list):
filterFields(self.fields[key], value)
allowed = []
for item in fields:
if isinstance(item, str):
allowed.append(item)
elif isinstance(item, dict):
allowed.append(list(item.keys())[0])
existing = set(self.fields)
allowed = set(allowed)
for field_name in existing - allowed:
self.fields.pop(field_name)
return self.fields
class BaseSerializer(serializers.ModelSerializer): class BaseSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(read_only=True) id = serializers.PrimaryKeyRelatedField(read_only=True)
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop("fields", None)
# Instantiate the superclass normally
super().__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
self.fields = filterFields(self, fields)

View File

@ -6,10 +6,10 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserSerializer
from .issue import IssueStateSerializer from .issue import IssueStateSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from plane.db.models import Cycle, CycleIssue, CycleFavorite from plane.db.models import Cycle, CycleIssue, CycleFavorite
class CycleWriteSerializer(BaseSerializer): class CycleWriteSerializer(BaseSerializer):
@ -20,7 +20,7 @@ class CycleWriteSerializer(BaseSerializer):
class CycleSerializer(BaseSerializer): class CycleSerializer(BaseSerializer):
owned_by = UserLiteSerializer(read_only=True) owned_by = UserSerializer(read_only=True)
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True) total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True) cancelled_issues = serializers.IntegerField(read_only=True)
@ -33,9 +33,9 @@ class CycleSerializer(BaseSerializer):
total_estimates = serializers.IntegerField(read_only=True) total_estimates = serializers.IntegerField(read_only=True)
completed_estimates = serializers.IntegerField(read_only=True) completed_estimates = serializers.IntegerField(read_only=True)
started_estimates = serializers.IntegerField(read_only=True) started_estimates = serializers.IntegerField(read_only=True)
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") workspace_detail = WorkSpaceSerializer(source="workspace",read_only=True)
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(read_only=True, source="project")
def get_assignees(self, obj): def get_assignees(self, obj):
members = [ members = [
{ {
@ -54,7 +54,7 @@ class CycleSerializer(BaseSerializer):
unique_list = [dict(item) for item in unique_objects] unique_list = [dict(item) for item in unique_objects]
return unique_list return unique_list
def get_labels(self, obj): def get_labels(self, obj):
labels = [ labels = [
{ {

View File

@ -2,12 +2,12 @@
from .base import BaseSerializer from .base import BaseSerializer
from plane.db.models import Estimate, EstimatePoint from plane.db.models import Estimate, EstimatePoint
from plane.api.serializers import WorkspaceLiteSerializer, ProjectLiteSerializer from plane.api.serializers import WorkSpaceSerializer, ProjectSerializer
class EstimateSerializer(BaseSerializer): class EstimateSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") workspace_detail = WorkSpaceSerializer(source="workspace", read_only=True)
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(read_only=True, source="project")
class Meta: class Meta:
model = Estimate model = Estimate
@ -27,18 +27,3 @@ class EstimatePointSerializer(BaseSerializer):
"workspace", "workspace",
"project", "project",
] ]
class EstimateReadSerializer(BaseSerializer):
points = EstimatePointSerializer(read_only=True, many=True)
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = Estimate
fields = "__all__"
read_only_fields = [
"points",
"name",
"description",
]

View File

@ -1,11 +1,11 @@
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from plane.db.models import ExporterHistory from plane.db.models import ExporterHistory
from .user import UserLiteSerializer from .user import UserSerializer
class ExporterHistorySerializer(BaseSerializer): class ExporterHistorySerializer(BaseSerializer):
initiated_by_detail = UserLiteSerializer(source="initiated_by", read_only=True) initiated_by_detail = UserSerializer(source="initiated_by",read_only=True)
class Meta: class Meta:
model = ExporterHistory model = ExporterHistory

View File

@ -1,15 +1,15 @@
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from plane.db.models import Importer from plane.db.models import Importer
class ImporterSerializer(BaseSerializer): class ImporterSerializer(BaseSerializer):
initiated_by_detail = UserLiteSerializer(source="initiated_by", read_only=True) initiated_by_detail = UserSerializer(source="initiated_by", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(source="workspace", read_only=True)
class Meta: class Meta:
model = Importer model = Importer

View File

@ -4,15 +4,14 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .issue import IssueFlatSerializer, LabelLiteSerializer from .issue import IssueFlatSerializer, LabelLiteSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from .state import StateLiteSerializer from .state import StateLiteSerializer
from .project import ProjectLiteSerializer from .user import UserSerializer
from .user import UserLiteSerializer
from plane.db.models import Inbox, InboxIssue, Issue from plane.db.models import Inbox, InboxIssue, Issue
class InboxSerializer(BaseSerializer): class InboxSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id","name","cover_image","icon_prop","emoji","description"), read_only=True)
pending_issue_count = serializers.IntegerField(read_only=True) pending_issue_count = serializers.IntegerField(read_only=True)
class Meta: class Meta:
@ -26,7 +25,7 @@ class InboxSerializer(BaseSerializer):
class InboxIssueSerializer(BaseSerializer): class InboxIssueSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True) issue_detail = IssueFlatSerializer(source="issue", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id","name","cover_image","icon_prop","emoji","description"), read_only=True)
class Meta: class Meta:
model = InboxIssue model = InboxIssue
@ -46,9 +45,9 @@ class InboxIssueLiteSerializer(BaseSerializer):
class IssueStateInboxSerializer(BaseSerializer): class IssueStateInboxSerializer(BaseSerializer):
state_detail = StateLiteSerializer(read_only=True, source="state") state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True) label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True) assignee_details = UserSerializer(source="assignees", read_only=True, many=True)
sub_issues_count = serializers.IntegerField(read_only=True) sub_issues_count = serializers.IntegerField(read_only=True)
bridge_id = serializers.UUIDField(read_only=True) bridge_id = serializers.UUIDField(read_only=True)
issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True) issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True)

View File

@ -6,11 +6,10 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserSerializer
from .state import StateSerializer, StateLiteSerializer from .state import StateSerializer, StateLiteSerializer
from .user import UserLiteSerializer from .project import ProjectSerializer
from .project import ProjectSerializer, ProjectLiteSerializer from .workspace import WorkSpaceSerializer
from .workspace import WorkspaceLiteSerializer
from plane.db.models import ( from plane.db.models import (
User, User,
Issue, Issue,
@ -54,7 +53,11 @@ class IssueFlatSerializer(BaseSerializer):
class IssueProjectLiteSerializer(BaseSerializer): class IssueProjectLiteSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
class Meta: class Meta:
model = Issue model = Issue
@ -71,9 +74,12 @@ class IssueProjectLiteSerializer(BaseSerializer):
## Find a better approach to save manytomany? ## Find a better approach to save manytomany?
class IssueCreateSerializer(BaseSerializer): class IssueCreateSerializer(BaseSerializer):
state_detail = StateSerializer(read_only=True, source="state") state_detail = StateSerializer(read_only=True, source="state")
created_by_detail = UserLiteSerializer(read_only=True, source="created_by") created_by_detail = UserSerializer(
project_detail = ProjectLiteSerializer(read_only=True, source="project") source="created_by",
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") read_only=True,
)
project_detail = ProjectSerializer(source="project", read_only=True)
workspace_detail = WorkSpaceSerializer(source="workspace", read_only=True)
assignees_list = serializers.ListField( assignees_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()), child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
@ -113,7 +119,11 @@ class IssueCreateSerializer(BaseSerializer):
] ]
def validate(self, data): def validate(self, data):
if data.get("start_date", None) is not None and data.get("target_date", None) is not None and data.get("start_date", None) > data.get("target_date", None): if (
data.get("start_date", None) is not None
and data.get("target_date", None) is not None
and data.get("start_date", None) > data.get("target_date", None)
):
raise serializers.ValidationError("Start date cannot exceed target date") raise serializers.ValidationError("Start date cannot exceed target date")
return data return data
@ -296,35 +306,19 @@ class IssueCreateSerializer(BaseSerializer):
class IssueActivitySerializer(BaseSerializer): class IssueActivitySerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor") actor_detail = UserSerializer(source="actor", read_only=True)
issue_detail = IssueFlatSerializer(read_only=True, source="issue") issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
class Meta: class Meta:
model = IssueActivity model = IssueActivity
fields = "__all__" fields = "__all__"
class IssueCommentSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
class Meta:
model = IssueComment
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"issue",
"created_by",
"updated_by",
"created_at",
"updated_at",
]
class IssuePropertySerializer(BaseSerializer): class IssuePropertySerializer(BaseSerializer):
class Meta: class Meta:
model = IssueProperty model = IssueProperty
@ -337,8 +331,14 @@ class IssuePropertySerializer(BaseSerializer):
class LabelSerializer(BaseSerializer): class LabelSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(
project_detail = ProjectLiteSerializer(source="project", read_only=True) source="workspace", fields=("id", "name", "slug"), read_only=True
)
project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
class Meta: class Meta:
model = Label model = Label
@ -399,12 +399,16 @@ class BlockerIssueSerializer(BaseSerializer):
read_only_fields = fields read_only_fields = fields
class IssueAssigneeSerializer(BaseSerializer): # class IssueAssigneeSerializer(BaseSerializer):
assignee_details = UserLiteSerializer(read_only=True, source="assignee") # assignee_details = UserSerializer(
# source="assignee",
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
# read_only=True,
# )
class Meta: # class Meta:
model = IssueAssignee # model = IssueAssignee
fields = "__all__" # fields = "__all__"
class CycleBaseSerializer(BaseSerializer): class CycleBaseSerializer(BaseSerializer):
@ -468,7 +472,11 @@ class IssueModuleDetailSerializer(BaseSerializer):
class IssueLinkSerializer(BaseSerializer): class IssueLinkSerializer(BaseSerializer):
created_by_detail = UserLiteSerializer(read_only=True, source="created_by") created_by_detail = UserSerializer(
source="created_by",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = IssueLink model = IssueLink
@ -522,7 +530,11 @@ class IssueReactionSerializer(BaseSerializer):
class IssueReactionLiteSerializer(BaseSerializer): class IssueReactionLiteSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor") actor_detail = UserSerializer(
source="actor",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = IssueReaction model = IssueReaction
@ -535,7 +547,11 @@ class IssueReactionLiteSerializer(BaseSerializer):
class CommentReactionLiteSerializer(BaseSerializer): class CommentReactionLiteSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor") actor_detail = UserSerializer(
source="actor",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = CommentReaction model = CommentReaction
@ -554,9 +570,7 @@ class CommentReactionSerializer(BaseSerializer):
read_only_fields = ["workspace", "project", "comment", "actor"] read_only_fields = ["workspace", "project", "comment", "actor"]
class IssueVoteSerializer(BaseSerializer): class IssueVoteSerializer(BaseSerializer):
class Meta: class Meta:
model = IssueVote model = IssueVote
fields = ["issue", "vote", "workspace_id", "project_id", "actor"] fields = ["issue", "vote", "workspace_id", "project_id", "actor"]
@ -564,12 +578,20 @@ class IssueVoteSerializer(BaseSerializer):
class IssueCommentSerializer(BaseSerializer): class IssueCommentSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor") actor_detail = UserSerializer(source="actor", read_only=True)
issue_detail = IssueFlatSerializer(read_only=True, source="issue") issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") source="project",
comment_reactions = CommentReactionLiteSerializer(read_only=True, many=True) fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
workspace_details = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
comment_reactions = CommentReactionLiteSerializer(read_only=True, many=True)
class Meta: class Meta:
model = IssueComment model = IssueComment
@ -588,7 +610,11 @@ class IssueCommentSerializer(BaseSerializer):
class IssueStateFlatSerializer(BaseSerializer): class IssueStateFlatSerializer(BaseSerializer):
state_detail = StateLiteSerializer(read_only=True, source="state") state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
class Meta: class Meta:
model = Issue model = Issue
@ -605,8 +631,17 @@ class IssueStateFlatSerializer(BaseSerializer):
class IssueStateSerializer(BaseSerializer): class IssueStateSerializer(BaseSerializer):
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True) label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
state_detail = StateLiteSerializer(read_only=True, source="state") state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True) source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
assignee_details = UserSerializer(
source="assignees",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
many=True,
)
sub_issues_count = serializers.IntegerField(read_only=True) sub_issues_count = serializers.IntegerField(read_only=True)
bridge_id = serializers.UUIDField(read_only=True) bridge_id = serializers.UUIDField(read_only=True)
attachment_count = serializers.IntegerField(read_only=True) attachment_count = serializers.IntegerField(read_only=True)
@ -618,11 +653,20 @@ class IssueStateSerializer(BaseSerializer):
class IssueSerializer(BaseSerializer): class IssueSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
state_detail = StateSerializer(read_only=True, source="state") state_detail = StateSerializer(read_only=True, source="state")
parent_detail = IssueStateFlatSerializer(read_only=True, source="parent") parent_detail = IssueStateFlatSerializer(read_only=True, source="parent")
label_details = LabelSerializer(read_only=True, source="labels", many=True) label_details = LabelSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True) assignee_details = UserSerializer(
source="assignees",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
many=True,
)
# List of issues blocked by this issue # List of issues blocked by this issue
blocked_issues = BlockedIssueSerializer(read_only=True, many=True) blocked_issues = BlockedIssueSerializer(read_only=True, many=True)
# List of issues that block this issue # List of issues that block this issue
@ -648,11 +692,24 @@ class IssueSerializer(BaseSerializer):
class IssueLiteSerializer(BaseSerializer): class IssueLiteSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") workspace_detail = WorkSpaceSerializer(
project_detail = ProjectLiteSerializer(read_only=True, source="project") source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
project_detail = ProjectSerializer(
source="project",
fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"),
read_only=True,
)
state_detail = StateLiteSerializer(read_only=True, source="state") state_detail = StateLiteSerializer(read_only=True, source="state")
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True) label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True) assignee_details = UserSerializer(
source="assignees",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
many=True,
)
sub_issues_count = serializers.IntegerField(read_only=True) sub_issues_count = serializers.IntegerField(read_only=True)
cycle_id = serializers.UUIDField(read_only=True) cycle_id = serializers.UUIDField(read_only=True)
module_id = serializers.UUIDField(read_only=True) module_id = serializers.UUIDField(read_only=True)

View File

@ -3,9 +3,9 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserSerializer
from .project import ProjectSerializer, ProjectLiteSerializer from .project import ProjectSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from .issue import IssueStateSerializer from .issue import IssueStateSerializer
from plane.db.models import ( from plane.db.models import (
@ -25,8 +25,12 @@ class ModuleWriteSerializer(BaseSerializer):
required=False, required=False,
) )
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = Module model = Module
@ -106,7 +110,7 @@ class ModuleFlatSerializer(BaseSerializer):
class ModuleIssueSerializer(BaseSerializer): class ModuleIssueSerializer(BaseSerializer):
module_detail = ModuleFlatSerializer(read_only=True, source="module") module_detail = ModuleFlatSerializer(read_only=True, source="module")
issue_detail = ProjectLiteSerializer(read_only=True, source="issue") issue_detail = ProjectSerializer(source="issue", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
sub_issues_count = serializers.IntegerField(read_only=True) sub_issues_count = serializers.IntegerField(read_only=True)
class Meta: class Meta:
@ -124,7 +128,11 @@ class ModuleIssueSerializer(BaseSerializer):
class ModuleLinkSerializer(BaseSerializer): class ModuleLinkSerializer(BaseSerializer):
created_by_detail = UserLiteSerializer(read_only=True, source="created_by") created_by_detail = UserSerializer(
source="created_by",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = ModuleLink model = ModuleLink
@ -151,9 +159,18 @@ class ModuleLinkSerializer(BaseSerializer):
class ModuleSerializer(BaseSerializer): class ModuleSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
lead_detail = UserLiteSerializer(read_only=True, source="lead") lead_detail = UserSerializer(
members_detail = UserLiteSerializer(read_only=True, many=True, source="members") source="lead",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
members_detail = UserSerializer(
source="members",
fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
many=True,
)
link_module = ModuleLinkSerializer(read_only=True, many=True) link_module = ModuleLinkSerializer(read_only=True, many=True)
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True) total_issues = serializers.IntegerField(read_only=True)

View File

@ -1,12 +1,16 @@
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserSerializer
from plane.db.models import Notification from plane.db.models import Notification
class NotificationSerializer(BaseSerializer): class NotificationSerializer(BaseSerializer):
triggered_by_details = UserLiteSerializer(read_only=True, source="triggered_by") triggered_by_details = UserSerializer(
source="triggered_by",
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = Notification model = Notification
fields = "__all__" fields = "__all__"

View File

@ -4,15 +4,19 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .issue import IssueFlatSerializer, LabelLiteSerializer from .issue import IssueFlatSerializer, LabelLiteSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label
class PageBlockSerializer(BaseSerializer): class PageBlockSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True) issue_detail = IssueFlatSerializer(source="issue", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = PageBlock model = PageBlock
@ -39,8 +43,12 @@ class PageSerializer(BaseSerializer):
required=False, required=False,
) )
blocks = PageBlockLiteSerializer(read_only=True, many=True) blocks = PageBlockLiteSerializer(read_only=True, many=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = Page model = Page

View File

@ -6,8 +6,8 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from plane.api.serializers.workspace import WorkSpaceSerializer, WorkspaceLiteSerializer from plane.api.serializers.workspace import WorkSpaceSerializer
from plane.api.serializers.user import UserLiteSerializer, UserAdminLiteSerializer from plane.api.serializers.user import UserSerializer
from plane.db.models import ( from plane.db.models import (
Project, Project,
ProjectMember, ProjectMember,
@ -19,7 +19,28 @@ from plane.db.models import (
class ProjectSerializer(BaseSerializer): class ProjectSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) # workspace = WorkSpaceSerializer(read_only=True)
default_assignee = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
project_lead = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
is_favorite = serializers.BooleanField(read_only=True)
total_members = serializers.IntegerField(read_only=True)
total_cycles = serializers.IntegerField(read_only=True)
total_modules = serializers.IntegerField(read_only=True)
is_member = serializers.BooleanField(read_only=True)
sort_order = serializers.FloatField(read_only=True)
member_role = serializers.IntegerField(read_only=True)
is_deployed = serializers.BooleanField(read_only=True)
workspace_detail = WorkSpaceSerializer(
source="workspace",
# fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = Project model = Project
@ -78,25 +99,16 @@ class ProjectSerializer(BaseSerializer):
raise serializers.ValidationError(detail="Project Identifier is already taken") raise serializers.ValidationError(detail="Project Identifier is already taken")
class ProjectLiteSerializer(BaseSerializer):
class Meta:
model = Project
fields = [
"id",
"identifier",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
read_only_fields = fields
class ProjectDetailSerializer(BaseSerializer): class ProjectDetailSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True) workspace = WorkSpaceSerializer(read_only=True)
default_assignee = UserLiteSerializer(read_only=True) default_assignee = UserSerializer(
project_lead = UserLiteSerializer(read_only=True) # fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
project_lead = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
total_members = serializers.IntegerField(read_only=True) total_members = serializers.IntegerField(read_only=True)
total_cycles = serializers.IntegerField(read_only=True) total_cycles = serializers.IntegerField(read_only=True)
@ -113,8 +125,11 @@ class ProjectDetailSerializer(BaseSerializer):
class ProjectMemberSerializer(BaseSerializer): class ProjectMemberSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True) workspace = WorkSpaceSerializer(read_only=True)
project = ProjectLiteSerializer(read_only=True) project = ProjectSerializer(fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
member = UserLiteSerializer(read_only=True) member = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = ProjectMember model = ProjectMember
@ -122,9 +137,24 @@ class ProjectMemberSerializer(BaseSerializer):
class ProjectMemberAdminSerializer(BaseSerializer): class ProjectMemberAdminSerializer(BaseSerializer):
workspace = WorkspaceLiteSerializer(read_only=True) workspace = WorkSpaceSerializer(
project = ProjectLiteSerializer(read_only=True) source="workspace",
member = UserAdminLiteSerializer(read_only=True) fields=("id", "name", "slug"),
read_only=True,
)
project = ProjectSerializer(fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
member = UserSerializer(
# fields=(
# "id",
# "first_name",
# "last_name",
# "avatar",
# "is_bot",
# "display_name",
# "email",
# ),
read_only=True,
)
class Meta: class Meta:
model = ProjectMember model = ProjectMember
@ -132,8 +162,11 @@ class ProjectMemberAdminSerializer(BaseSerializer):
class ProjectMemberInviteSerializer(BaseSerializer): class ProjectMemberInviteSerializer(BaseSerializer):
project = ProjectLiteSerializer(read_only=True) project = ProjectSerializer(fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True) workspace = WorkSpaceSerializer(
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = ProjectMemberInvite model = ProjectMemberInvite
@ -147,7 +180,7 @@ class ProjectIdentifierSerializer(BaseSerializer):
class ProjectFavoriteSerializer(BaseSerializer): class ProjectFavoriteSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
class Meta: class Meta:
model = ProjectFavorite model = ProjectFavorite
@ -159,7 +192,10 @@ class ProjectFavoriteSerializer(BaseSerializer):
class ProjectMemberLiteSerializer(BaseSerializer): class ProjectMemberLiteSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True) member = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
is_subscribed = serializers.BooleanField(read_only=True) is_subscribed = serializers.BooleanField(read_only=True)
class Meta: class Meta:
@ -169,8 +205,12 @@ class ProjectMemberLiteSerializer(BaseSerializer):
class ProjectDeployBoardSerializer(BaseSerializer): class ProjectDeployBoardSerializer(BaseSerializer):
project_details = ProjectLiteSerializer(read_only=True, source="project") project_details = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") workspace_detail = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = ProjectDeployBoard model = ProjectDeployBoard

View File

@ -1,14 +1,14 @@
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from plane.db.models import State from plane.db.models import State
class StateSerializer(BaseSerializer): class StateSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace") workspace_detail = WorkSpaceSerializer(source="workspace", read_only=True)
project_detail = ProjectLiteSerializer(read_only=True, source="project") project_detail = ProjectSerializer(source="project", read_only=True)
class Meta: class Meta:
model = State model = State

View File

@ -33,42 +33,6 @@ class UserSerializer(BaseSerializer):
return bool(obj.first_name) or bool(obj.last_name) return bool(obj.first_name) or bool(obj.last_name)
class UserLiteSerializer(BaseSerializer):
class Meta:
model = User
fields = [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
read_only_fields = [
"id",
"is_bot",
]
class UserAdminLiteSerializer(BaseSerializer):
class Meta:
model = User
fields = [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
"email",
]
read_only_fields = [
"id",
"is_bot",
]
class ChangePasswordSerializer(serializers.Serializer): class ChangePasswordSerializer(serializers.Serializer):
model = User model = User

View File

@ -3,16 +3,20 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkSpaceSerializer
from .project import ProjectLiteSerializer from .project import ProjectSerializer
from plane.db.models import IssueView, IssueViewFavorite from plane.db.models import IssueView, IssueViewFavorite
from plane.utils.issue_filters import issue_filters from plane.utils.issue_filters import issue_filters
class IssueViewSerializer(BaseSerializer): class IssueViewSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True) is_favorite = serializers.BooleanField(read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True) project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True) workspace_detail = WorkSpaceSerializer(
source="workspace",
fields=("id", "name", "slug"),
read_only=True,
)
class Meta: class Meta:
model = IssueView model = IssueView

View File

@ -3,7 +3,7 @@ from rest_framework import serializers
# Module imports # Module imports
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer, UserAdminLiteSerializer from .user import UserSerializer
from plane.db.models import ( from plane.db.models import (
User, User,
@ -17,7 +17,10 @@ from plane.db.models import (
class WorkSpaceSerializer(BaseSerializer): class WorkSpaceSerializer(BaseSerializer):
owner = UserLiteSerializer(read_only=True) owner = UserSerializer(
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
total_members = serializers.IntegerField(read_only=True) total_members = serializers.IntegerField(read_only=True)
total_issues = serializers.IntegerField(read_only=True) total_issues = serializers.IntegerField(read_only=True)
@ -33,30 +36,16 @@ class WorkSpaceSerializer(BaseSerializer):
"owner", "owner",
] ]
class WorkspaceLiteSerializer(BaseSerializer):
class Meta:
model = Workspace
fields = [
"name",
"slug",
"id",
]
read_only_fields = fields
class WorkSpaceMemberSerializer(BaseSerializer): class WorkSpaceMemberSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True) member = UserSerializer(
workspace = WorkspaceLiteSerializer(read_only=True) # fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name" ,"email"),
read_only=True,
class Meta: )
model = WorkspaceMember workspace = WorkSpaceSerializer(
fields = "__all__" fields=("id", "name", "slug"),
read_only=True,
)
class WorkspaceMemberAdminSerializer(BaseSerializer):
member = UserAdminLiteSerializer(read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True)
class Meta: class Meta:
model = WorkspaceMember model = WorkspaceMember
@ -66,7 +55,11 @@ class WorkspaceMemberAdminSerializer(BaseSerializer):
class WorkSpaceMemberInviteSerializer(BaseSerializer): class WorkSpaceMemberInviteSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True) workspace = WorkSpaceSerializer(read_only=True)
total_members = serializers.IntegerField(read_only=True) total_members = serializers.IntegerField(read_only=True)
created_by_detail = UserLiteSerializer(read_only=True, source="created_by") created_by_detail = UserSerializer(
source="created_by",
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
)
class Meta: class Meta:
model = WorkspaceMemberInvite model = WorkspaceMemberInvite
@ -74,7 +67,12 @@ class WorkSpaceMemberInviteSerializer(BaseSerializer):
class TeamSerializer(BaseSerializer): class TeamSerializer(BaseSerializer):
members_detail = UserLiteSerializer(read_only=True, source="members", many=True) members_detail = UserSerializer(
source="members",
# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"),
read_only=True,
many=True,
)
members = serializers.ListField( members = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()), child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
write_only=True, write_only=True,

View File

@ -56,6 +56,10 @@ class CycleViewSet(BaseViewSet):
permission_classes = [ permission_classes = [
ProjectEntityPermission, ProjectEntityPermission,
] ]
# def get_serializer_class(self):
# return (
# CycleSerializer(nested_fields={"owned_by":("id", "first_name", "last_name", "avatar", "is_bot", "display_name")})
# )
def perform_create(self, serializer): def perform_create(self, serializer):
serializer.save( serializer.save(
@ -148,13 +152,15 @@ class CycleViewSet(BaseViewSet):
.prefetch_related( .prefetch_related(
Prefetch( Prefetch(
"issue_cycle__issue__assignees", "issue_cycle__issue__assignees",
queryset=User.objects.only("avatar", "first_name", "id").distinct(), queryset=User.objects.only(
"avatar", "first_name", "id").distinct(),
) )
) )
.prefetch_related( .prefetch_related(
Prefetch( Prefetch(
"issue_cycle__issue__labels", "issue_cycle__issue__labels",
queryset=Label.objects.only("name", "color", "id").distinct(), queryset=Label.objects.only(
"name", "color", "id").distinct(),
) )
) )
.order_by("-is_favorite", "name") .order_by("-is_favorite", "name")
@ -172,7 +178,8 @@ class CycleViewSet(BaseViewSet):
# All Cycles # All Cycles
if cycle_view == "all": if cycle_view == "all":
return Response( return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data, status=status.HTTP_200_OK
) )
# Current Cycle # Current Cycle
@ -182,7 +189,8 @@ class CycleViewSet(BaseViewSet):
end_date__gte=timezone.now(), end_date__gte=timezone.now(),
) )
data = CycleSerializer(queryset, many=True).data data = CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data
if len(data): if len(data):
assignee_distribution = ( assignee_distribution = (
@ -256,14 +264,16 @@ class CycleViewSet(BaseViewSet):
if cycle_view == "upcoming": if cycle_view == "upcoming":
queryset = queryset.filter(start_date__gt=timezone.now()) queryset = queryset.filter(start_date__gt=timezone.now())
return Response( return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data, status=status.HTTP_200_OK
) )
# Completed Cycles # Completed Cycles
if cycle_view == "completed": if cycle_view == "completed":
queryset = queryset.filter(end_date__lt=timezone.now()) queryset = queryset.filter(end_date__lt=timezone.now())
return Response( return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data, status=status.HTTP_200_OK
) )
# Draft Cycles # Draft Cycles
@ -274,16 +284,19 @@ class CycleViewSet(BaseViewSet):
) )
return Response( return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data, status=status.HTTP_200_OK
) )
# Incomplete Cycles # Incomplete Cycles
if cycle_view == "incomplete": if cycle_view == "incomplete":
queryset = queryset.filter( queryset = queryset.filter(
Q(end_date__gte=timezone.now().date()) | Q(end_date__isnull=True), Q(end_date__gte=timezone.now().date()) | Q(
end_date__isnull=True),
) )
return Response( return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}], many=True).data, status=status.HTTP_200_OK
) )
return Response( return Response(
@ -306,7 +319,8 @@ class CycleViewSet(BaseViewSet):
request.data.get("start_date", None) is not None request.data.get("start_date", None) is not None
and request.data.get("end_date", None) is not None and request.data.get("end_date", None) is not None
): ):
serializer = CycleSerializer(data=request.data) serializer = CycleSerializer(data=request.data, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}])
if serializer.is_valid(): if serializer.is_valid():
serializer.save( serializer.save(
project_id=project_id, project_id=project_id,
@ -342,7 +356,8 @@ class CycleViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
serializer = CycleWriteSerializer(cycle, data=request.data, partial=True) serializer = CycleWriteSerializer(
cycle, data=request.data, partial=True)
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
@ -418,7 +433,8 @@ class CycleViewSet(BaseViewSet):
.order_by("label_name") .order_by("label_name")
) )
data = CycleSerializer(queryset).data data = CycleSerializer(queryset, fields=["id", "created_by", "created_at", "updated_at", "updated_by", "project", "workspace", "name", "description", "start_date", "end_date", "owned_by", "view_props", "sort_order", "is_favorite", "total_issues", "cancelled_issues", "completed_issues", "started_issues", "unstarted_issues"
, "backlog_issues", "assignees", "labels", "total_estimates", "completed_estimates", "started_estimates",{"workspace_detail": ["id", "name","slug"]},{ "project_detail": ["id", "name", "cover_image", "icon_prop", "emoji", "description"]}, {"owned_by": ["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}]).data
data["distribution"] = { data["distribution"] = {
"assignees": assignee_distribution, "assignees": assignee_distribution,
"labels": label_distribution, "labels": label_distribution,
@ -486,7 +502,8 @@ class CycleIssueViewSet(BaseViewSet):
super() super()
.get_queryset() .get_queryset()
.annotate( .annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("issue_id")) sub_issues_count=Issue.issue_objects.filter(
parent=OuterRef("issue_id"))
.order_by() .order_by()
.annotate(count=Func(F("id"), function="Count")) .annotate(count=Func(F("id"), function="Count"))
.values("count") .values("count")
@ -512,7 +529,8 @@ class CycleIssueViewSet(BaseViewSet):
issues = ( issues = (
Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id) Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id)
.annotate( .annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id")) sub_issues_count=Issue.issue_objects.filter(
parent=OuterRef("id"))
.order_by() .order_by()
.annotate(count=Func(F("id"), function="Count")) .annotate(count=Func(F("id"), function="Count"))
.values("count") .values("count")

View File

@ -13,7 +13,6 @@ from plane.db.models import Project, Estimate, EstimatePoint
from plane.api.serializers import ( from plane.api.serializers import (
EstimateSerializer, EstimateSerializer,
EstimatePointSerializer, EstimatePointSerializer,
EstimateReadSerializer,
) )
@ -51,10 +50,38 @@ class BulkEstimatePointEndpoint(BaseViewSet):
def list(self, request, slug, project_id): def list(self, request, slug, project_id):
try: try:
estimates = Estimate.objects.filter( estimates = (
workspace__slug=slug, project_id=project_id Estimate.objects.filter(workspace__slug=slug, project_id=project_id)
).prefetch_related("points").select_related("workspace", "project") .prefetch_related("points")
serializer = EstimateReadSerializer(estimates, many=True) .select_related("workspace", "project")
)
serializer = EstimateSerializer(
estimates,
fields=[
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
"name",
"points",
"description",
],
many=True,
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -79,7 +106,31 @@ class BulkEstimatePointEndpoint(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
estimate_serializer = EstimateSerializer(data=request.data.get("estimate")) estimate_serializer = EstimateSerializer(
data=request.data.get("estimate"),
fields=[
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
"name",
"description",
],
)
if not estimate_serializer.is_valid(): if not estimate_serializer.is_valid():
return Response( return Response(
estimate_serializer.errors, status=status.HTTP_400_BAD_REQUEST estimate_serializer.errors, status=status.HTTP_400_BAD_REQUEST
@ -137,7 +188,32 @@ class BulkEstimatePointEndpoint(BaseViewSet):
estimate = Estimate.objects.get( estimate = Estimate.objects.get(
pk=estimate_id, workspace__slug=slug, project_id=project_id pk=estimate_id, workspace__slug=slug, project_id=project_id
) )
serializer = EstimateReadSerializer(estimate) serializer = EstimateSerializer(
estimate,
fields=[
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
"name",
"points",
"description",
],
)
return Response( return Response(
serializer.data, serializer.data,
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
@ -170,7 +246,31 @@ class BulkEstimatePointEndpoint(BaseViewSet):
estimate = Estimate.objects.get(pk=estimate_id) estimate = Estimate.objects.get(pk=estimate_id)
estimate_serializer = EstimateSerializer( estimate_serializer = EstimateSerializer(
estimate, data=request.data.get("estimate"), partial=True estimate,
data=request.data.get("estimate"),
fields=[
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
"name",
"description",
],
partial=True,
) )
if not estimate_serializer.is_valid(): if not estimate_serializer.is_valid():
return Response( return Response(
@ -211,7 +311,9 @@ class BulkEstimatePointEndpoint(BaseViewSet):
try: try:
EstimatePoint.objects.bulk_update( EstimatePoint.objects.bulk_update(
updated_estimate_points, ["value"], batch_size=10, updated_estimate_points,
["value"],
batch_size=10,
) )
except IntegrityError as e: except IntegrityError as e:
return Response( return Response(
@ -219,7 +321,9 @@ class BulkEstimatePointEndpoint(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
estimate_point_serializer = EstimatePointSerializer(estimate_points, many=True) estimate_point_serializer = EstimatePointSerializer(
estimate_points, many=True
)
return Response( return Response(
{ {
"estimate": estimate_serializer.data, "estimate": estimate_serializer.data,

View File

@ -23,11 +23,11 @@ class ExportIssuesEndpoint(BaseAPIView):
try: try:
# Get the workspace # Get the workspace
workspace = Workspace.objects.get(slug=slug) workspace = Workspace.objects.get(slug=slug)
provider = request.data.get("provider", False) provider = request.data.get("provider", False)
multiple = request.data.get("multiple", False) multiple = request.data.get("multiple", False)
project_ids = request.data.get("project", []) project_ids = request.data.get("project", [])
if provider in ["csv", "xlsx", "json"]: if provider in ["csv", "xlsx", "json"]:
if not project_ids: if not project_ids:
project_ids = Project.objects.filter( project_ids = Project.objects.filter(
@ -77,14 +77,38 @@ class ExportIssuesEndpoint(BaseAPIView):
try: try:
exporter_history = ExporterHistory.objects.filter( exporter_history = ExporterHistory.objects.filter(
workspace__slug=slug workspace__slug=slug
).select_related("workspace","initiated_by") ).select_related("workspace", "initiated_by")
if request.GET.get("per_page", False) and request.GET.get("cursor", False): if request.GET.get("per_page", False) and request.GET.get("cursor", False):
return self.paginate( return self.paginate(
request=request, request=request,
queryset=exporter_history, queryset=exporter_history,
on_results=lambda exporter_history: ExporterHistorySerializer( on_results=lambda exporter_history: ExporterHistorySerializer(
exporter_history, many=True exporter_history,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"initiated_by",
"status",
"url",
"token",
"project",
"provider",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
],
many=True,
).data, ).data,
) )
else: else:

View File

@ -14,7 +14,7 @@ from django.conf import settings
from .base import BaseAPIView from .base import BaseAPIView
from plane.api.permissions import ProjectEntityPermission from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Workspace, Project from plane.db.models import Workspace, Project
from plane.api.serializers import ProjectLiteSerializer, WorkspaceLiteSerializer from plane.api.serializers import ProjectSerializer, WorkSpaceSerializer
class GPTIntegrationEndpoint(BaseAPIView): class GPTIntegrationEndpoint(BaseAPIView):
@ -57,8 +57,26 @@ class GPTIntegrationEndpoint(BaseAPIView):
{ {
"response": text, "response": text,
"response_html": text_html, "response_html": text_html,
"project_detail": ProjectLiteSerializer(project).data, "project_detail": ProjectSerializer(
"workspace_detail": WorkspaceLiteSerializer(workspace).data, project,
fields=[
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
"created_by",
"updated_by",
"created_at",
"updated_at",
],
read_only=True,
).data,
"workspace_detail": WorkSpaceSerializer(
workspace,
fields=["id", "name", "slug"],
).data,
}, },
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
) )

View File

@ -42,7 +42,6 @@ from plane.utils.html_processor import strip_tags
class ServiceIssueImportSummaryEndpoint(BaseAPIView): class ServiceIssueImportSummaryEndpoint(BaseAPIView):
def get(self, request, slug, service): def get(self, request, slug, service):
try: try:
if service == "github": if service == "github":
@ -177,7 +176,47 @@ class ImportServiceEndpoint(BaseAPIView):
) )
service_importer.delay(service, importer.id) service_importer.delay(service, importer.id)
serializer = ImporterSerializer(importer) serializer = ImporterSerializer(
importer,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"workspace",
"project",
"service",
"status",
"initiated_by",
"metadata",
"config",
"data",
"token",
"imported_data",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
],
)
return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_201_CREATED)
if service == "jira": if service == "jira":
@ -213,7 +252,47 @@ class ImportServiceEndpoint(BaseAPIView):
) )
service_importer.delay(service, importer.id) service_importer.delay(service, importer.id)
serializer = ImporterSerializer(importer) serializer = ImporterSerializer(
importer,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"workspace",
"project",
"service",
"status",
"initiated_by",
"metadata",
"config",
"data",
"token",
"imported_data",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
],
)
return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response( return Response(
@ -243,7 +322,48 @@ class ImportServiceEndpoint(BaseAPIView):
.order_by("-created_at") .order_by("-created_at")
.select_related("initiated_by", "project", "workspace") .select_related("initiated_by", "project", "workspace")
) )
serializer = ImporterSerializer(imports, many=True) serializer = ImporterSerializer(
imports,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"workspace",
"project",
"service",
"status",
"initiated_by",
"metadata",
"config",
"data",
"token",
"imported_data",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
],
many=True,
)
return Response(serializer.data) return Response(serializer.data)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -284,7 +404,49 @@ class ImportServiceEndpoint(BaseAPIView):
importer = Importer.objects.get( importer = Importer.objects.get(
pk=pk, service=service, workspace__slug=slug pk=pk, service=service, workspace__slug=slug
) )
serializer = ImporterSerializer(importer, data=request.data, partial=True) serializer = ImporterSerializer(
importer,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"workspace",
"project",
"service",
"status",
"initiated_by",
"metadata",
"config",
"data",
"token",
"imported_data",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
],
data=request.data,
partial=True,
)
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)

View File

@ -152,7 +152,22 @@ class InboxIssueViewSet(BaseViewSet):
) )
) )
) )
issues_data = IssueStateInboxSerializer(issues, many=True).data issues_data = IssueStateInboxSerializer(
issues,
fields=[
{
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
}
],
many=True,
).data
return Response( return Response(
issues_data, issues_data,
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
@ -222,7 +237,19 @@ class InboxIssueViewSet(BaseViewSet):
source=request.data.get("source", "in-app"), source=request.data.get("source", "in-app"),
) )
serializer = IssueStateInboxSerializer(issue) serializer = IssueStateInboxSerializer(
issue,
nested_fields={
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -237,10 +264,17 @@ class InboxIssueViewSet(BaseViewSet):
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id 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(workspace__slug=slug, project_id=project_id, member=request.user) project_member = ProjectMember.objects.get(
workspace__slug=slug, project_id=project_id, member=request.user
)
# 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(request.user.id): if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST) request.user.id
):
return Response(
{"error": "You cannot edit inbox issues"},
status=status.HTTP_400_BAD_REQUEST,
)
# Get issue data # Get issue data
issue_data = request.data.pop("issue", False) issue_data = request.data.pop("issue", False)
@ -251,15 +285,99 @@ class InboxIssueViewSet(BaseViewSet):
) )
# Only allow guests and viewers to edit name and description # Only allow guests and viewers to edit name and description
if project_member.role <= 10: if project_member.role <= 10:
# viewers and guests since only viewers and guests # viewers and guests since only viewers and guests
issue_data = { issue_data = {
"name": issue_data.get("name", issue.name), "name": issue_data.get("name", issue.name),
"description_html": issue_data.get("description_html", issue.description_html), "description_html": issue_data.get(
"description": issue_data.get("description", issue.description) "description_html", issue.description_html
),
"description": issue_data.get("description", issue.description),
} }
issue_serializer = IssueCreateSerializer( issue_serializer = IssueCreateSerializer(
issue, data=issue_data, partial=True issue,
data=issue_data,
fields=[
{
"created_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
{
"state_detail": [
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"description",
"color",
"slug",
"sequence",
"group",
"default",
"project",
"workspace",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
"assignees_list",
"blockers_list",
"labels_list",
"blocks_list",
"PRIORITY_CHOICES",
"parent",
"state",
"estimate_point",
"name",
"description",
"description_html",
"description_stripped",
"priority",
"start_date",
"target_date",
"assignees",
"sequence_id",
"labels",
"sort_order",
"completed_at",
"archived_at",
],
partial=True,
) )
if issue_serializer.is_valid(): if issue_serializer.is_valid():
@ -287,7 +405,30 @@ class InboxIssueViewSet(BaseViewSet):
# Only project admins and members can edit inbox issue attributes # Only project admins and members can edit inbox issue attributes
if project_member.role > 10: if project_member.role > 10:
serializer = InboxIssueSerializer( serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True inbox_issue,
fields=[
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
"id",
"created_at",
"updated_at",
"inbox",
"issue",
"status",
"snoozed_till",
"duplicate_to",
"source",
],
data=request.data,
partial=True,
) )
if serializer.is_valid(): if serializer.is_valid():
@ -300,7 +441,9 @@ class InboxIssueViewSet(BaseViewSet):
project_id=project_id, project_id=project_id,
) )
state = State.objects.filter( state = State.objects.filter(
group="cancelled", workspace__slug=slug, project_id=project_id group="cancelled",
workspace__slug=slug,
project_id=project_id,
).first() ).first()
if state is not None: if state is not None:
issue.state = state issue.state = state
@ -318,7 +461,9 @@ class InboxIssueViewSet(BaseViewSet):
if issue.state.name == "Triage": if issue.state.name == "Triage":
# Move to default state # Move to default state
state = State.objects.filter( state = State.objects.filter(
workspace__slug=slug, project_id=project_id, default=True workspace__slug=slug,
project_id=project_id,
default=True,
).first() ).first()
if state is not None: if state is not None:
issue.state = state issue.state = state
@ -327,7 +472,9 @@ class InboxIssueViewSet(BaseViewSet):
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else: else:
return Response(InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK) return Response(
InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK
)
except InboxIssue.DoesNotExist: except InboxIssue.DoesNotExist:
return Response( return Response(
{"error": "Inbox Issue does not exist"}, {"error": "Inbox Issue does not exist"},
@ -348,7 +495,19 @@ class InboxIssueViewSet(BaseViewSet):
issue = Issue.objects.get( issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
) )
serializer = IssueStateInboxSerializer(issue) serializer = IssueStateInboxSerializer(
issue,
nested_fields={
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -363,15 +522,25 @@ class InboxIssueViewSet(BaseViewSet):
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id 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(workspace__slug=slug, project_id=project_id, member=request.user) project_member = ProjectMember.objects.get(
workspace__slug=slug, project_id=project_id, member=request.user
)
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id): if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(
return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST) request.user.id
):
return Response(
{"error": "You cannot delete inbox issue"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox_issue.delete() inbox_issue.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
except InboxIssue.DoesNotExist: except InboxIssue.DoesNotExist:
return Response({"error": "Inbox Issue does not exists"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox Issue does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
return Response( return Response(
@ -389,7 +558,10 @@ class InboxIssuePublicViewSet(BaseViewSet):
] ]
def get_queryset(self): def get_queryset(self):
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id")) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=self.kwargs.get("slug"),
project_id=self.kwargs.get("project_id"),
)
if project_deploy_board is not None: if project_deploy_board is not None:
return self.filter_queryset( return self.filter_queryset(
super() super()
@ -407,9 +579,14 @@ class InboxIssuePublicViewSet(BaseViewSet):
def list(self, request, slug, project_id, inbox_id): def list(self, request, slug, project_id, inbox_id):
try: try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
if project_deploy_board.inbox is None: if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox is not enabled for this Project Board"},
status=status.HTTP_400_BAD_REQUEST,
)
filters = issue_filters(request.query_params, "GET") filters = issue_filters(request.query_params, "GET")
issues = ( issues = (
@ -452,13 +629,29 @@ class InboxIssuePublicViewSet(BaseViewSet):
) )
) )
) )
issues_data = IssueStateInboxSerializer(issues, many=True).data issues_data = IssueStateInboxSerializer(
issues,
nested_fields={
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
many=True,
).data
return Response( return Response(
issues_data, issues_data,
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
) )
except ProjectDeployBoard.DoesNotExist: except ProjectDeployBoard.DoesNotExist:
return Response({"error": "Project Deploy Board does not exist"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Project Deploy Board does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
return Response( return Response(
@ -468,9 +661,14 @@ class InboxIssuePublicViewSet(BaseViewSet):
def create(self, request, slug, project_id, inbox_id): def create(self, request, slug, project_id, inbox_id):
try: try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
if project_deploy_board.inbox is None: if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox is not enabled for this Project Board"},
status=status.HTTP_400_BAD_REQUEST,
)
if not request.data.get("issue", {}).get("name", False): if not request.data.get("issue", {}).get("name", False):
return Response( return Response(
@ -527,7 +725,19 @@ class InboxIssuePublicViewSet(BaseViewSet):
source=request.data.get("source", "in-app"), source=request.data.get("source", "in-app"),
) )
serializer = IssueStateInboxSerializer(issue) serializer = IssueStateInboxSerializer(
issue,
nested_fields={
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -538,33 +748,124 @@ class InboxIssuePublicViewSet(BaseViewSet):
def partial_update(self, request, slug, project_id, inbox_id, pk): def partial_update(self, request, slug, project_id, inbox_id, pk):
try: try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
if project_deploy_board.inbox is None: if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox is not enabled for this Project Board"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox_issue = InboxIssue.objects.get( inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
) )
# Get the project member # Get the project member
if str(inbox_issue.created_by_id) != str(request.user.id): if str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "You cannot edit inbox issues"},
status=status.HTTP_400_BAD_REQUEST,
)
# Get issue data # Get issue data
issue_data = request.data.pop("issue", False) issue_data = request.data.pop("issue", False)
issue = Issue.objects.get( issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
) )
# viewers and guests since only viewers and guests # viewers and guests since only viewers and guests
issue_data = { issue_data = {
"name": issue_data.get("name", issue.name), "name": issue_data.get("name", issue.name),
"description_html": issue_data.get("description_html", issue.description_html), "description_html": issue_data.get(
"description": issue_data.get("description", issue.description) "description_html", issue.description_html
),
"description": issue_data.get("description", issue.description),
} }
issue_serializer = IssueCreateSerializer( issue_serializer = IssueCreateSerializer(
issue, data=issue_data, partial=True issue,
data=issue_data,
fields=[
{
"created_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
{
"state_detail": [
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"description",
"color",
"slug",
"sequence",
"group",
"default",
"project",
"workspace",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
"assignees_list",
"blockers_list",
"labels_list",
"blocks_list",
"PRIORITY_CHOICES",
"parent",
"state",
"estimate_point",
"name",
"description",
"description_html",
"description_stripped",
"priority",
"start_date",
"target_date",
"assignees",
"sequence_id",
"labels",
"sort_order",
"completed_at",
"archived_at",
],
partial=True,
) )
if issue_serializer.is_valid(): if issue_serializer.is_valid():
@ -600,17 +901,34 @@ class InboxIssuePublicViewSet(BaseViewSet):
def retrieve(self, request, slug, project_id, inbox_id, pk): def retrieve(self, request, slug, project_id, inbox_id, pk):
try: try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
if project_deploy_board.inbox is None: if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox is not enabled for this Project Board"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox_issue = InboxIssue.objects.get( inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
) )
issue = Issue.objects.get( issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
) )
serializer = IssueStateInboxSerializer(issue) serializer = IssueStateInboxSerializer(
issue,
nested_fields={
"assignee_details": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
@ -621,25 +939,35 @@ class InboxIssuePublicViewSet(BaseViewSet):
def destroy(self, request, slug, project_id, inbox_id, pk): def destroy(self, request, slug, project_id, inbox_id, pk):
try: try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id) project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
if project_deploy_board.inbox is None: if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox is not enabled for this Project Board"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox_issue = InboxIssue.objects.get( inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
) )
if str(inbox_issue.created_by_id) != str(request.user.id): if str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "You cannot delete inbox issue"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox_issue.delete() inbox_issue.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
except InboxIssue.DoesNotExist: except InboxIssue.DoesNotExist:
return Response({"error": "Inbox Issue does not exists"}, status=status.HTTP_400_BAD_REQUEST) return Response(
{"error": "Inbox Issue does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
return Response( return Response(
{"error": "Something went wrong please try again later"}, {"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )

View File

@ -281,6 +281,86 @@ class IssueViewSet(BaseViewSet):
serializer = IssueCreateSerializer( serializer = IssueCreateSerializer(
data=request.data, data=request.data,
fields=[
{
"created_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
{
"state_detail": [
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"description",
"color",
"slug",
"sequence",
"group",
"default",
"project",
"workspace",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
"id",
"created_at",
"created_by",
"updated_at",
"updated_by",
"workspace",
"project",
"assignees_list",
"blockers_list",
"labels_list",
"blocks_list",
"PRIORITY_CHOICES",
"parent",
"state",
"estimate_point",
"name",
"description",
"description_html",
"description_stripped",
"priority",
"start_date",
"target_date",
"assignees",
"sequence_id",
"labels",
"sort_order",
"completed_at",
"archived_at",
],
context={ context={
"project_id": project_id, "project_id": project_id,
"workspace_id": project.workspace_id, "workspace_id": project.workspace_id,
@ -493,8 +573,34 @@ class IssueActivityEndpoint(BaseAPIView):
.order_by("created_at") .order_by("created_at")
.select_related("actor", "issue", "project", "workspace") .select_related("actor", "issue", "project", "workspace")
) )
issue_activities = IssueActivitySerializer(issue_activities, many=True).data issue_activities = IssueActivitySerializer(
issue_comments = IssueCommentSerializer(issue_comments, many=True).data issue_activities,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
many=True,
).data
issue_comments = IssueCommentSerializer(
issue_comments,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
many=True,
).data
result_list = sorted( result_list = sorted(
chain(issue_activities, issue_comments), chain(issue_activities, issue_comments),
@ -522,6 +628,9 @@ class IssueCommentViewSet(BaseViewSet):
"workspace__id", "workspace__id",
] ]
# def get_serializer_class(self):
# return IssueCommentSerializer(nested_fields={"actor_detail":("id", "first_name", "last_name", "avatar", "is_bot", "display_name")})
def perform_create(self, serializer): def perform_create(self, serializer):
serializer.save( serializer.save(
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
@ -550,7 +659,19 @@ class IssueCommentViewSet(BaseViewSet):
issue_id=str(self.kwargs.get("issue_id", None)), issue_id=str(self.kwargs.get("issue_id", None)),
project_id=str(self.kwargs.get("project_id", None)), project_id=str(self.kwargs.get("project_id", None)),
current_instance=json.dumps( current_instance=json.dumps(
IssueCommentSerializer(current_instance).data, IssueCommentSerializer(
current_instance,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
), ),
) )
@ -571,7 +692,19 @@ class IssueCommentViewSet(BaseViewSet):
issue_id=str(self.kwargs.get("issue_id", None)), issue_id=str(self.kwargs.get("issue_id", None)),
project_id=str(self.kwargs.get("project_id", None)), project_id=str(self.kwargs.get("project_id", None)),
current_instance=json.dumps( current_instance=json.dumps(
IssueCommentSerializer(current_instance).data, IssueCommentSerializer(
current_instance,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
), ),
) )
@ -769,7 +902,9 @@ class SubIssuesEndpoint(BaseAPIView):
.order_by("state_group") .order_by("state_group")
) )
result = {item["state_group"]: item["state_count"] for item in state_distribution} result = {
item["state_group"]: item["state_count"] for item in state_distribution
}
serializer = IssueLiteSerializer( serializer = IssueLiteSerializer(
sub_issues, sub_issues,
@ -1507,7 +1642,19 @@ class IssueCommentPublicViewSet(BaseViewSet):
else "EXTERNAL" else "EXTERNAL"
) )
serializer = IssueCommentSerializer(data=request.data) serializer = IssueCommentSerializer(
data=request.data,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
)
if serializer.is_valid(): if serializer.is_valid():
serializer.save( serializer.save(
project_id=project_id, project_id=project_id,
@ -1547,7 +1694,19 @@ class IssueCommentPublicViewSet(BaseViewSet):
workspace__slug=slug, pk=pk, actor=request.user workspace__slug=slug, pk=pk, actor=request.user
) )
serializer = IssueCommentSerializer( serializer = IssueCommentSerializer(
comment, data=request.data, partial=True comment,
data=request.data,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
partial=True,
) )
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
@ -1558,7 +1717,19 @@ class IssueCommentPublicViewSet(BaseViewSet):
issue_id=str(issue_id), issue_id=str(issue_id),
project_id=str(project_id), project_id=str(project_id),
current_instance=json.dumps( current_instance=json.dumps(
IssueCommentSerializer(comment).data, IssueCommentSerializer(
comment,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
), ),
) )
@ -1567,7 +1738,8 @@ class IssueCommentPublicViewSet(BaseViewSet):
except (IssueComment.DoesNotExist, ProjectDeployBoard.DoesNotExist): except (IssueComment.DoesNotExist, ProjectDeployBoard.DoesNotExist):
return Response( return Response(
{"error": "IssueComent Does not exists"}, {"error": "IssueComent Does not exists"},
status=status.HTTP_400_BAD_REQUEST,) status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, issue_id, pk): def destroy(self, request, slug, project_id, issue_id, pk):
try: try:
@ -1590,7 +1762,19 @@ class IssueCommentPublicViewSet(BaseViewSet):
issue_id=str(issue_id), issue_id=str(issue_id),
project_id=str(project_id), project_id=str(project_id),
current_instance=json.dumps( current_instance=json.dumps(
IssueCommentSerializer(comment).data, IssueCommentSerializer(
comment,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
), ),
) )
@ -1835,9 +2019,11 @@ class ExportIssuesEndpoint(BaseAPIView):
def post(self, request, slug): def post(self, request, slug):
try: try:
issue_export_task.delay( issue_export_task.delay(
email=request.user.email, data=request.data, slug=slug ,exporter_name=request.user.first_name email=request.user.email,
data=request.data,
slug=slug,
exporter_name=request.user.first_name,
) )
return Response( return Response(
@ -1851,4 +2037,4 @@ class ExportIssuesEndpoint(BaseAPIView):
return Response( return Response(
{"error": "Something went wrong please try again later"}, {"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )

View File

@ -91,10 +91,10 @@ class ProjectViewSet(BaseViewSet):
ProjectBasePermission, ProjectBasePermission,
] ]
def get_serializer_class(self, *args, **kwargs): # def get_serializer_class(self, *args, **kwargs):
if self.action == "update" or self.action == "partial_update": # if self.action == "update" or self.action == "partial_update":
return ProjectSerializer # return ProjectSerializer(fields=['id', {'workspace_detail': ["id", "name", "slug"]}, 'created_at', 'updated_at', 'name', 'description', 'description_text', 'description_html', 'network', 'identifier', 'emoji', 'icon_prop', 'module_view', 'cycle_view', 'issue_views_view', 'page_view', 'inbox_view', 'cover_image', 'archive_in', 'close_in', 'created_by', 'updated_by', 'workspace', 'default_assignee', 'project_lead', 'estimate', 'default_state', 'sort_order'],)
return ProjectDetailSerializer # return ProjectDetailSerializer
def get_queryset(self): def get_queryset(self):
subquery = ProjectFavorite.objects.filter( subquery = ProjectFavorite.objects.filter(
@ -216,7 +216,38 @@ class ProjectViewSet(BaseViewSet):
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},
fields=[
"id",
{"workspace_detail": ["id", "name", "slug"]},
"created_at",
"updated_at",
"name",
"description",
"description_text",
"description_html",
"network",
"identifier",
"emoji",
"icon_prop",
"module_view",
"cycle_view",
"issue_views_view",
"page_view",
"inbox_view",
"cover_image",
"archive_in",
"close_in",
"created_by",
"updated_by",
"workspace",
"default_assignee",
"project_lead",
"estimate",
"default_state",
"sort_order",
],
context={"workspace_id": workspace.id},
) )
if serializer.is_valid(): if serializer.is_valid():
serializer.save() serializer.save()
@ -330,6 +361,36 @@ class ProjectViewSet(BaseViewSet):
serializer = ProjectSerializer( serializer = ProjectSerializer(
project, project,
data={**request.data}, data={**request.data},
fields=[
"id",
{"workspace_detail": ["id", "name", "slug"]},
"created_at",
"updated_at",
"name",
"description",
"description_text",
"description_html",
"network",
"identifier",
"emoji",
"icon_prop",
"module_view",
"cycle_view",
"issue_views_view",
"page_view",
"inbox_view",
"cover_image",
"archive_in",
"close_in",
"created_by",
"updated_by",
"workspace",
"default_assignee",
"project_lead",
"estimate",
"default_state",
"sort_order",
],
context={"workspace_id": workspace.id}, context={"workspace_id": workspace.id},
partial=True, partial=True,
) )
@ -1263,7 +1324,7 @@ class ProjectDeployBoardIssuesPublicEndpoint(BaseAPIView):
workspace__slug=slug, project_id=project_id workspace__slug=slug, project_id=project_id
).values("id", "name", "color", "parent") ).values("id", "name", "color", "parent")
## Grouping the results # Grouping the results
group_by = request.GET.get("group_by", False) group_by = request.GET.get("group_by", False)
if group_by: if group_by:
issues = group_results(issues, group_by) issues = group_results(issues, group_by)

View File

@ -42,7 +42,36 @@ class StateViewSet(BaseViewSet):
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
try: try:
serializer = StateSerializer(data=request.data) serializer = StateSerializer(
data=request.data,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"description",
"color",
"slug",
"sequence",
"group",
"default",
"project",
"workspace",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
],
)
if serializer.is_valid(): if serializer.is_valid():
serializer.save(project_id=project_id) serializer.save(project_id=project_id)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
@ -62,7 +91,37 @@ class StateViewSet(BaseViewSet):
def list(self, request, slug, project_id): def list(self, request, slug, project_id):
try: try:
state_dict = dict() state_dict = dict()
states = StateSerializer(self.get_queryset(), many=True).data states = StateSerializer(
self.get_queryset(),
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"description",
"color",
"slug",
"sequence",
"group",
"default",
"project",
"workspace",
{"workspace_detail": ["id", "name", "slug"]},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
],
many=True,
).data
for key, value in groupby( for key, value in groupby(
sorted(states, key=lambda state: state["group"]), sorted(states, key=lambda state: state["group"]),
@ -82,7 +141,9 @@ class StateViewSet(BaseViewSet):
try: try:
state = State.objects.get( state = State.objects.get(
~Q(name="Triage"), ~Q(name="Triage"),
pk=pk, project_id=project_id, workspace__slug=slug, pk=pk,
project_id=project_id,
workspace__slug=slug,
) )
if state.default: if state.default:

View File

@ -147,7 +147,18 @@ class UserActivityEndpoint(BaseAPIView, BasePaginator):
request=request, request=request,
queryset=queryset, queryset=queryset,
on_results=lambda issue_activities: IssueActivitySerializer( on_results=lambda issue_activities: IssueActivitySerializer(
issue_activities, many=True issue_activities,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
many=True,
).data, ).data,
) )
except Exception as e: except Exception as e:

View File

@ -42,12 +42,11 @@ from plane.api.serializers import (
WorkSpaceMemberSerializer, WorkSpaceMemberSerializer,
TeamSerializer, TeamSerializer,
WorkSpaceMemberInviteSerializer, WorkSpaceMemberInviteSerializer,
UserLiteSerializer, UserSerializer,
ProjectMemberSerializer, ProjectMemberSerializer,
WorkspaceThemeSerializer, WorkspaceThemeSerializer,
IssueActivitySerializer, IssueActivitySerializer,
IssueLiteSerializer, IssueLiteSerializer,
WorkspaceMemberAdminSerializer,
) )
from plane.api.views.base import BaseAPIView from plane.api.views.base import BaseAPIView
from . import BaseViewSet from . import BaseViewSet
@ -164,8 +163,8 @@ class WorkSpaceViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
## Handling unique integrity error for now # Handling unique integrity error for now
## TODO: Extend this to handle other common errors which are not automatically handled by APIException # TODO: Extend this to handle other common errors which are not automatically handled by APIException
except IntegrityError as e: except IntegrityError as e:
if "already exists" in str(e): if "already exists" in str(e):
return Response( return Response(
@ -300,7 +299,31 @@ class InviteWorkspaceEndpoint(BaseAPIView):
{ {
"error": "Some users are already member of workspace", "error": "Some users are already member of workspace",
"workspace_users": WorkSpaceMemberSerializer( "workspace_users": WorkSpaceMemberSerializer(
workspace_members, many=True workspace_members,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"logo",
"owner",
"slug",
"organization_size",
{"workspace": ["id", "name", "slug"]},
{
"member": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
],
many=True,
).data, ).data,
}, },
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
@ -542,7 +565,7 @@ class UserWorkspaceInvitationsEndpoint(BaseViewSet):
class WorkSpaceMemberViewSet(BaseViewSet): class WorkSpaceMemberViewSet(BaseViewSet):
serializer_class = WorkspaceMemberAdminSerializer serializer_class = WorkSpaceMemberSerializer
model = WorkspaceMember model = WorkspaceMember
permission_classes = [ permission_classes = [
@ -591,7 +614,32 @@ class WorkSpaceMemberViewSet(BaseViewSet):
) )
serializer = WorkSpaceMemberSerializer( serializer = WorkSpaceMemberSerializer(
workspace_member, data=request.data, partial=True workspace_member,
data=request.data,
partial=True,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"logo",
"owner",
"slug",
"organization_size",
{"workspace": ["id", "name", "slug"]},
{
"member": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
],
) )
if serializer.is_valid(): if serializer.is_valid():
@ -725,7 +773,18 @@ class TeamMemberViewSet(BaseViewSet):
users = list(set(request.data.get("members", [])).difference(members)) users = list(set(request.data.get("members", [])).difference(members))
users = User.objects.filter(pk__in=users) users = User.objects.filter(pk__in=users)
serializer = UserLiteSerializer(users, many=True) serializer = UserSerializer(
users,
fields=[
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
many=True,
)
return Response( return Response(
{ {
"error": f"{len(users)} of the member(s) are not a part of the workspace", "error": f"{len(users)} of the member(s) are not a part of the workspace",
@ -791,14 +850,95 @@ class UserLastProjectWithWorkspaceEndpoint(BaseAPIView):
) )
workspace = Workspace.objects.get(pk=last_workspace_id) workspace = Workspace.objects.get(pk=last_workspace_id)
workspace_serializer = WorkSpaceSerializer(workspace) workspace_serializer = WorkSpaceSerializer(
workspace,
fields=[
"id",
{
"owner": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
"created_at",
"updated_at",
"name",
"logo",
"slug",
"organization_size",
"created_by",
"updated_by",
],
)
project_member = ProjectMember.objects.filter( project_member = ProjectMember.objects.filter(
workspace_id=last_workspace_id, member=request.user workspace_id=last_workspace_id, member=request.user
).select_related("workspace", "project", "member", "workspace__owner") ).select_related("workspace", "project", "member", "workspace__owner")
project_member_serializer = ProjectMemberSerializer( project_member_serializer = ProjectMemberSerializer(
project_member, many=True project_member,
fields=[
"id",
{
"workspace": [
"id",
{
"owner": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
"created_at",
"updated_at",
"name",
"logo",
"slug",
"organization_size",
"created_by",
"updated_by",
]
},
{
"project": [
"id",
"identifier",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{
"member": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
"created_at",
"updated_at",
"comment",
"role",
"view_props",
"default_props",
"preferences",
"sort_order",
"created_by",
"updated_by",
],
many=True,
) )
return Response( return Response(
@ -825,7 +965,32 @@ class WorkspaceMemberUserEndpoint(BaseAPIView):
workspace_member = WorkspaceMember.objects.get( workspace_member = WorkspaceMember.objects.get(
member=request.user, workspace__slug=slug member=request.user, workspace__slug=slug
) )
serializer = WorkSpaceMemberSerializer(workspace_member) serializer = WorkSpaceMemberSerializer(
workspace_member,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"logo",
"owner",
"slug",
"organization_size",
{"workspace": ["id", "name", "slug"]},
{
"member": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
],
)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except (Workspace.DoesNotExist, WorkspaceMember.DoesNotExist): except (Workspace.DoesNotExist, WorkspaceMember.DoesNotExist):
return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN) return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN)
@ -1209,7 +1374,18 @@ class WorkspaceUserActivityEndpoint(BaseAPIView):
request=request, request=request,
queryset=queryset, queryset=queryset,
on_results=lambda issue_activities: IssueActivitySerializer( on_results=lambda issue_activities: IssueActivitySerializer(
issue_activities, many=True issue_activities,
nested_fields={
"actor_detail": (
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
)
},
many=True,
).data, ).data,
) )
except Exception as e: except Exception as e:
@ -1417,7 +1593,7 @@ class WorkspaceUserProfileIssuesEndpoint(BaseAPIView):
issues = IssueLiteSerializer(issue_queryset, many=True).data issues = IssueLiteSerializer(issue_queryset, many=True).data
## Grouping the results # Grouping the results
group_by = request.GET.get("group_by", False) group_by = request.GET.get("group_by", False)
if group_by: if group_by:
return Response( return Response(
@ -1464,8 +1640,34 @@ class WorkspaceMembersEndpoint(BaseAPIView):
workspace__slug=slug, workspace__slug=slug,
member__is_bot=False, member__is_bot=False,
).select_related("workspace", "member") ).select_related("workspace", "member")
serialzier = WorkSpaceMemberSerializer(workspace_members, many=True) serializer = WorkSpaceMemberSerializer(
return Response(serialzier.data, status=status.HTTP_200_OK) workspace_members,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"name",
"logo",
"owner",
"slug",
"organization_size",
{"workspace": ["id", "name", "slug"]},
{
"member": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
]
},
],
many=True,
)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
return Response( return Response(

View File

@ -161,7 +161,47 @@ def service_importer(service, importer_id):
if settings.PROXY_BASE_URL: if settings.PROXY_BASE_URL:
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
import_data_json = json.dumps( import_data_json = json.dumps(
ImporterSerializer(importer).data, ImporterSerializer(
importer,
fields=[
"id",
"created_by",
"created_at",
"updated_at",
"updated_by",
"workspace",
"project",
"service",
"status",
"initiated_by",
"metadata",
"config",
"data",
"token",
"imported_data",
{
"initiated_by_detail": [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
],
},
{
"project_detail": [
"id",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
},
{"workspace_detail": ["id", "name", "slug"]},
],
).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
) )
res = requests.post( res = requests.post(

View File

@ -1103,7 +1103,7 @@ def issue_activity(
for issue_activity in issue_activities_created: for issue_activity in issue_activities_created:
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
issue_activity_json = json.dumps( issue_activity_json = json.dumps(
IssueActivitySerializer(issue_activity).data, IssueActivitySerializer(issue_activity,fields=[{"actor_detail":["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}]).data,
cls=DjangoJSONEncoder, cls=DjangoJSONEncoder,
) )
_ = requests.post( _ = requests.post(