diff --git a/apiserver/plane/api/serializers/__init__.py b/apiserver/plane/api/serializers/__init__.py index 66ced0a06..205d3a24d 100644 --- a/apiserver/plane/api/serializers/__init__.py +++ b/apiserver/plane/api/serializers/__init__.py @@ -14,7 +14,6 @@ from .project import ( ProjectMemberInviteSerializer, ProjectIdentifierSerializer, ProjectFavoriteSerializer, - ProjectLiteSerializer, ProjectMemberLiteSerializer, ProjectDeployBoardSerializer, ProjectMemberAdminSerializer, @@ -30,7 +29,7 @@ from .issue import ( IssuePropertySerializer, BlockerIssueSerializer, BlockedIssueSerializer, - IssueAssigneeSerializer, + # IssueAssigneeSerializer, LabelSerializer, IssueSerializer, IssueFlatSerializer, diff --git a/apiserver/plane/api/serializers/base.py b/apiserver/plane/api/serializers/base.py index 3d772b14a..75d8b732e 100644 --- a/apiserver/plane/api/serializers/base.py +++ b/apiserver/plane/api/serializers/base.py @@ -1,5 +1,22 @@ 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): id = serializers.PrimaryKeyRelatedField(read_only=True) @@ -7,18 +24,10 @@ class BaseSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): # Don't pass the 'fields' arg up to the superclass fields = kwargs.pop("fields", None) - remove_nested_fields = kwargs.pop("remove_nested_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. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) - if remove_nested_fields: - for field_name in remove_nested_fields: - for fields in remove_nested_fields[field_name]: - self.fields[field_name].fields.pop(fields) + self.fields = filterFields(self, fields) diff --git a/apiserver/plane/api/serializers/cycle.py b/apiserver/plane/api/serializers/cycle.py index 2290efac9..c141f71f1 100644 --- a/apiserver/plane/api/serializers/cycle.py +++ b/apiserver/plane/api/serializers/cycle.py @@ -9,7 +9,7 @@ from .base import BaseSerializer from .user import UserSerializer from .issue import IssueStateSerializer from .workspace import WorkSpaceSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from plane.db.models import Cycle, CycleIssue, CycleFavorite class CycleWriteSerializer(BaseSerializer): @@ -20,10 +20,7 @@ class CycleWriteSerializer(BaseSerializer): class CycleSerializer(BaseSerializer): - owned_by = UserSerializer( - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) + owned_by = UserSerializer(read_only=True) is_favorite = serializers.BooleanField(read_only=True) total_issues = serializers.IntegerField(read_only=True) cancelled_issues = serializers.IntegerField(read_only=True) @@ -36,12 +33,8 @@ class CycleSerializer(BaseSerializer): total_estimates = serializers.IntegerField(read_only=True) completed_estimates = serializers.IntegerField(read_only=True) started_estimates = serializers.IntegerField(read_only=True) - workspace_detail = WorkSpaceSerializer( - source="workspace", - fields=("id", "name", "slug"), - read_only=True, - ) - project_detail = ProjectLiteSerializer(read_only=True, source="project") + workspace_detail = WorkSpaceSerializer(source="workspace",read_only=True) + project_detail = ProjectSerializer(read_only=True, source="project") def get_assignees(self, obj): members = [ diff --git a/apiserver/plane/api/serializers/estimate.py b/apiserver/plane/api/serializers/estimate.py index 798e1ebfd..c39d80a82 100644 --- a/apiserver/plane/api/serializers/estimate.py +++ b/apiserver/plane/api/serializers/estimate.py @@ -2,7 +2,7 @@ from .base import BaseSerializer from plane.db.models import Estimate, EstimatePoint -from plane.api.serializers import WorkSpaceSerializer, ProjectLiteSerializer +from plane.api.serializers import WorkSpaceSerializer, ProjectSerializer class EstimateSerializer(BaseSerializer): @@ -11,7 +11,7 @@ class EstimateSerializer(BaseSerializer): fields=("id", "name", "slug"), read_only=True, ) - project_detail = ProjectLiteSerializer(read_only=True, source="project") + project_detail = ProjectSerializer(read_only=True, source="project", fields=("id","name","cover_image","icon_prop","emoji","description")) class Meta: model = Estimate @@ -40,7 +40,7 @@ class EstimateReadSerializer(BaseSerializer): fields=("id", "name", "slug"), read_only=True, ) - 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: model = Estimate diff --git a/apiserver/plane/api/serializers/exporter.py b/apiserver/plane/api/serializers/exporter.py index b01b58ff3..cf0ab29e7 100644 --- a/apiserver/plane/api/serializers/exporter.py +++ b/apiserver/plane/api/serializers/exporter.py @@ -5,11 +5,7 @@ from .user import UserSerializer class ExporterHistorySerializer(BaseSerializer): - initiated_by_detail = UserSerializer( - source="initiated_by", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) + initiated_by_detail = UserSerializer(source="initiated_by",read_only=True) class Meta: model = ExporterHistory diff --git a/apiserver/plane/api/serializers/importer.py b/apiserver/plane/api/serializers/importer.py index f90c66f74..7408a2e56 100644 --- a/apiserver/plane/api/serializers/importer.py +++ b/apiserver/plane/api/serializers/importer.py @@ -1,18 +1,14 @@ # Module imports from .base import BaseSerializer from .user import UserSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from .workspace import WorkSpaceSerializer from plane.db.models import Importer class ImporterSerializer(BaseSerializer): - initiated_by_detail = UserSerializer( - source="initiated_by", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) - project_detail = ProjectLiteSerializer(source="project", read_only=True) + initiated_by_detail = UserSerializer(source="initiated_by",read_only=True) + project_detail = ProjectSerializer(source="project", fields=("id","name","cover_image","icon_prop","emoji","description"), read_only=True) workspace_detail = WorkSpaceSerializer(source="workspace", read_only=True) class Meta: diff --git a/apiserver/plane/api/serializers/inbox.py b/apiserver/plane/api/serializers/inbox.py index 68bce788e..748f572e5 100644 --- a/apiserver/plane/api/serializers/inbox.py +++ b/apiserver/plane/api/serializers/inbox.py @@ -4,15 +4,14 @@ from rest_framework import serializers # Module imports from .base import BaseSerializer from .issue import IssueFlatSerializer, LabelLiteSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from .state import StateLiteSerializer -from .project import ProjectLiteSerializer from .user import UserSerializer from plane.db.models import Inbox, InboxIssue, Issue 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) class Meta: @@ -26,7 +25,7 @@ class InboxSerializer(BaseSerializer): class InboxIssueSerializer(BaseSerializer): 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: model = InboxIssue @@ -46,14 +45,9 @@ class InboxIssueLiteSerializer(BaseSerializer): class IssueStateInboxSerializer(BaseSerializer): 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) - assignee_details = UserSerializer( - source="assignees", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - many=True, - ) + assignee_details = UserSerializer(source="assignees", read_only=True, many=True) sub_issues_count = serializers.IntegerField(read_only=True) bridge_id = serializers.UUIDField(read_only=True) issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True) diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index d8a629e8e..fb58972c5 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -8,7 +8,7 @@ from rest_framework import serializers from .base import BaseSerializer from .user import UserSerializer from .state import StateSerializer, StateLiteSerializer -from .project import ProjectSerializer, ProjectLiteSerializer +from .project import ProjectSerializer from .workspace import WorkSpaceSerializer from plane.db.models import ( User, @@ -53,7 +53,7 @@ class IssueFlatSerializer(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: model = Issue @@ -70,12 +70,8 @@ class IssueProjectLiteSerializer(BaseSerializer): ## Find a better approach to save manytomany? class IssueCreateSerializer(BaseSerializer): state_detail = StateSerializer(read_only=True, source="state") - created_by_detail = UserSerializer( - source="created_by", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) - project_detail = ProjectLiteSerializer(read_only=True, source="project") + created_by_detail = UserSerializer(source="created_by", read_only=True,) + project_detail = ProjectSerializer(source="project", fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True) workspace_detail = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), @@ -307,47 +303,15 @@ class IssueCreateSerializer(BaseSerializer): class IssueActivitySerializer(BaseSerializer): - actor_detail = UserSerializer( - source="actor", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) + actor_detail = UserSerializer(source="actor", read_only=True) 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: model = IssueActivity fields = "__all__" -class IssueCommentSerializer(BaseSerializer): - actor_detail = UserSerializer( - source="actor", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) - issue_detail = IssueFlatSerializer(read_only=True, source="issue") - project_detail = ProjectLiteSerializer(read_only=True, source="project") - workspace_detail = WorkSpaceSerializer( - source="workspace", - fields=("id", "name", "slug"), - read_only=True, - ) - - class Meta: - model = IssueComment - fields = "__all__" - read_only_fields = [ - "workspace", - "project", - "issue", - "created_by", - "updated_by", - "created_at", - "updated_at", - ] - - class IssuePropertySerializer(BaseSerializer): class Meta: model = IssueProperty @@ -363,7 +327,7 @@ class LabelSerializer(BaseSerializer): workspace_detail = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), 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: model = Label @@ -424,16 +388,16 @@ class BlockerIssueSerializer(BaseSerializer): read_only_fields = fields -class IssueAssigneeSerializer(BaseSerializer): - assignee_details = UserSerializer( - source="assignee", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) +# class IssueAssigneeSerializer(BaseSerializer): +# assignee_details = UserSerializer( +# source="assignee", +# fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), +# read_only=True, +# ) - class Meta: - model = IssueAssignee - fields = "__all__" +# class Meta: +# model = IssueAssignee +# fields = "__all__" class CycleBaseSerializer(BaseSerializer): @@ -603,13 +567,9 @@ class IssueVoteSerializer(BaseSerializer): class IssueCommentSerializer(BaseSerializer): - actor_detail = UserSerializer( - source="actor", - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), - read_only=True, - ) + actor_detail = UserSerializer(source="actor", read_only=True) 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) workspace_details = WorkSpaceSerializer( source="workspace", @@ -635,7 +595,7 @@ class IssueCommentSerializer(BaseSerializer): class IssueStateFlatSerializer(BaseSerializer): 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: model = Issue @@ -652,7 +612,7 @@ class IssueStateFlatSerializer(BaseSerializer): class IssueStateSerializer(BaseSerializer): label_details = LabelLiteSerializer(read_only=True, source="labels", many=True) 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) assignee_details = UserSerializer( source="assignees", fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), @@ -670,7 +630,7 @@ class IssueStateSerializer(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") parent_detail = IssueStateFlatSerializer(read_only=True, source="parent") label_details = LabelSerializer(read_only=True, source="labels", many=True) @@ -710,7 +670,7 @@ class IssueLiteSerializer(BaseSerializer): fields=("id", "name", "slug"), read_only=True, ) - 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 = StateLiteSerializer(read_only=True, source="state") label_details = LabelLiteSerializer(read_only=True, source="labels", many=True) assignee_details = UserSerializer( diff --git a/apiserver/plane/api/serializers/module.py b/apiserver/plane/api/serializers/module.py index f3cead1fb..67b2af89b 100644 --- a/apiserver/plane/api/serializers/module.py +++ b/apiserver/plane/api/serializers/module.py @@ -4,7 +4,7 @@ from rest_framework import serializers # Module imports from .base import BaseSerializer from .user import UserSerializer -from .project import ProjectSerializer, ProjectLiteSerializer +from .project import ProjectSerializer from .workspace import WorkSpaceSerializer from .issue import IssueStateSerializer @@ -25,7 +25,7 @@ class ModuleWriteSerializer(BaseSerializer): 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 = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), @@ -110,7 +110,7 @@ class ModuleFlatSerializer(BaseSerializer): class ModuleIssueSerializer(BaseSerializer): 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) class Meta: @@ -159,7 +159,7 @@ class ModuleLinkSerializer(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 = UserSerializer( source="lead", fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), diff --git a/apiserver/plane/api/serializers/page.py b/apiserver/plane/api/serializers/page.py index 0b3c087ab..b562d9c7d 100644 --- a/apiserver/plane/api/serializers/page.py +++ b/apiserver/plane/api/serializers/page.py @@ -5,13 +5,13 @@ from rest_framework import serializers from .base import BaseSerializer from .issue import IssueFlatSerializer, LabelLiteSerializer from .workspace import WorkSpaceSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label class PageBlockSerializer(BaseSerializer): 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 = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), @@ -43,7 +43,7 @@ class PageSerializer(BaseSerializer): required=False, ) 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 = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), diff --git a/apiserver/plane/api/serializers/project.py b/apiserver/plane/api/serializers/project.py index bc9d1e74c..db1414298 100644 --- a/apiserver/plane/api/serializers/project.py +++ b/apiserver/plane/api/serializers/project.py @@ -19,9 +19,26 @@ from plane.db.models import ( class ProjectSerializer(BaseSerializer): + # 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"), + # fields=("id", "name", "slug"), read_only=True, ) @@ -82,21 +99,6 @@ class ProjectSerializer(BaseSerializer): 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): workspace = WorkSpaceSerializer(read_only=True) default_assignee = UserSerializer( @@ -123,7 +125,7 @@ class ProjectDetailSerializer(BaseSerializer): class ProjectMemberSerializer(BaseSerializer): 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 = UserSerializer( fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), read_only=True, @@ -140,7 +142,7 @@ class ProjectMemberAdminSerializer(BaseSerializer): fields=("id", "name", "slug"), read_only=True, ) - project = ProjectLiteSerializer(read_only=True) + project = ProjectSerializer(fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True) member = UserSerializer( fields=( "id", @@ -160,7 +162,7 @@ class ProjectMemberAdminSerializer(BaseSerializer): class ProjectMemberInviteSerializer(BaseSerializer): - project = ProjectLiteSerializer(read_only=True) + project = ProjectSerializer(fields=("id", "name", "cover_image", "icon_prop", "emoji", "description"), read_only=True) workspace = WorkSpaceSerializer( fields=("id", "name", "slug"), read_only=True, @@ -178,7 +180,7 @@ class ProjectIdentifierSerializer(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: model = ProjectFavorite @@ -203,7 +205,7 @@ class ProjectMemberLiteSerializer(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 = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), diff --git a/apiserver/plane/api/serializers/state.py b/apiserver/plane/api/serializers/state.py index a8badefd0..81cbb2227 100644 --- a/apiserver/plane/api/serializers/state.py +++ b/apiserver/plane/api/serializers/state.py @@ -1,7 +1,7 @@ # Module imports from .base import BaseSerializer from .workspace import WorkSpaceSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from plane.db.models import State @@ -12,7 +12,7 @@ class StateSerializer(BaseSerializer): fields=("id", "name", "slug"), read_only=True, ) - 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: model = State diff --git a/apiserver/plane/api/serializers/view.py b/apiserver/plane/api/serializers/view.py index e9f926a6b..902d7fb2c 100644 --- a/apiserver/plane/api/serializers/view.py +++ b/apiserver/plane/api/serializers/view.py @@ -4,14 +4,14 @@ from rest_framework import serializers # Module imports from .base import BaseSerializer from .workspace import WorkSpaceSerializer -from .project import ProjectLiteSerializer +from .project import ProjectSerializer from plane.db.models import IssueView, IssueViewFavorite from plane.utils.issue_filters import issue_filters class IssueViewSerializer(BaseSerializer): 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 = WorkSpaceSerializer( source="workspace", fields=("id", "name", "slug"), diff --git a/apiserver/plane/api/serializers/workspace.py b/apiserver/plane/api/serializers/workspace.py index a94a397d7..dd4f924ed 100644 --- a/apiserver/plane/api/serializers/workspace.py +++ b/apiserver/plane/api/serializers/workspace.py @@ -18,7 +18,7 @@ from plane.db.models import ( class WorkSpaceSerializer(BaseSerializer): owner = UserSerializer( - fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), + # fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name"), read_only=True, ) total_members = serializers.IntegerField(read_only=True) @@ -37,7 +37,6 @@ class WorkSpaceSerializer(BaseSerializer): ] - class WorkSpaceMemberSerializer(BaseSerializer): member = UserSerializer( fields=("id", "first_name", "last_name", "avatar", "is_bot", "display_name" ,"email"), @@ -53,30 +52,6 @@ class WorkSpaceMemberSerializer(BaseSerializer): fields = "__all__" -# class WorkspaceMemberAdminSerializer(BaseSerializer): -# member = UserSerializer( -# fields=( -# "id", -# "first_name", -# "last_name", -# "avatar", -# "is_bot", -# "display_name", -# "email", -# ), -# read_only=True, -# ) - -# workspace = WorkSpaceSerializer( -# fields=("id", "name", "slug"), -# read_only=True, -# ) - -# class Meta: -# model = WorkspaceMember -# fields = "__all__" - - class WorkSpaceMemberInviteSerializer(BaseSerializer): workspace = WorkSpaceSerializer(read_only=True) total_members = serializers.IntegerField(read_only=True) diff --git a/apiserver/plane/api/views/cycle.py b/apiserver/plane/api/views/cycle.py index a3d89fa81..bb8a7b331 100644 --- a/apiserver/plane/api/views/cycle.py +++ b/apiserver/plane/api/views/cycle.py @@ -56,6 +56,10 @@ class CycleViewSet(BaseViewSet): permission_classes = [ 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): serializer.save( @@ -148,13 +152,15 @@ class CycleViewSet(BaseViewSet): .prefetch_related( Prefetch( "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( "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") @@ -172,7 +178,8 @@ class CycleViewSet(BaseViewSet): # All Cycles if cycle_view == "all": 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 @@ -182,7 +189,8 @@ class CycleViewSet(BaseViewSet): 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): assignee_distribution = ( @@ -256,14 +264,16 @@ class CycleViewSet(BaseViewSet): if cycle_view == "upcoming": queryset = queryset.filter(start_date__gt=timezone.now()) 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 if cycle_view == "completed": queryset = queryset.filter(end_date__lt=timezone.now()) 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 @@ -274,16 +284,19 @@ class CycleViewSet(BaseViewSet): ) 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 if cycle_view == "incomplete": 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( - 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( @@ -306,7 +319,8 @@ class CycleViewSet(BaseViewSet): request.data.get("start_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(): serializer.save( project_id=project_id, @@ -342,7 +356,8 @@ class CycleViewSet(BaseViewSet): 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(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) @@ -418,7 +433,8 @@ class CycleViewSet(BaseViewSet): .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"] = { "assignees": assignee_distribution, "labels": label_distribution, @@ -486,7 +502,8 @@ class CycleIssueViewSet(BaseViewSet): super() .get_queryset() .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() .annotate(count=Func(F("id"), function="Count")) .values("count") @@ -512,7 +529,8 @@ class CycleIssueViewSet(BaseViewSet): issues = ( Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id) .annotate( - sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id")) + sub_issues_count=Issue.issue_objects.filter( + parent=OuterRef("id")) .order_by() .annotate(count=Func(F("id"), function="Count")) .values("count") diff --git a/apiserver/plane/api/views/exporter.py b/apiserver/plane/api/views/exporter.py index 7e14aa82f..11cde6cb6 100644 --- a/apiserver/plane/api/views/exporter.py +++ b/apiserver/plane/api/views/exporter.py @@ -23,11 +23,11 @@ class ExportIssuesEndpoint(BaseAPIView): try: # Get the workspace workspace = Workspace.objects.get(slug=slug) - + provider = request.data.get("provider", False) multiple = request.data.get("multiple", False) project_ids = request.data.get("project", []) - + if provider in ["csv", "xlsx", "json"]: if not project_ids: project_ids = Project.objects.filter( @@ -77,14 +77,38 @@ class ExportIssuesEndpoint(BaseAPIView): try: exporter_history = ExporterHistory.objects.filter( 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): return self.paginate( request=request, queryset=exporter_history, 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, ) else: diff --git a/apiserver/plane/api/views/gpt.py b/apiserver/plane/api/views/gpt.py index 3f44d496c..e35eeb58c 100644 --- a/apiserver/plane/api/views/gpt.py +++ b/apiserver/plane/api/views/gpt.py @@ -14,7 +14,7 @@ from django.conf import settings from .base import BaseAPIView from plane.api.permissions import ProjectEntityPermission from plane.db.models import Workspace, Project -from plane.api.serializers import ProjectLiteSerializer, WorkSpaceSerializer +from plane.api.serializers import ProjectSerializer, WorkSpaceSerializer class GPTIntegrationEndpoint(BaseAPIView): @@ -57,10 +57,25 @@ class GPTIntegrationEndpoint(BaseAPIView): { "response": text, "response_html": text_html, - "project_detail": ProjectLiteSerializer(project).data, + "project_detail": ProjectSerializer( + 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"), + fields=["id", "name", "slug"], ).data, }, status=status.HTTP_200_OK, diff --git a/apiserver/plane/api/views/importer.py b/apiserver/plane/api/views/importer.py index 0a92b3850..2501f3699 100644 --- a/apiserver/plane/api/views/importer.py +++ b/apiserver/plane/api/views/importer.py @@ -177,7 +177,36 @@ class ImportServiceEndpoint(BaseAPIView): ) service_importer.delay(service, importer.id) - serializer = ImporterSerializer(importer) + serializer = ImporterSerializer( + importer, + fields={ + "id": [], + "created_by": [], + "created_at": [], + "updated_at": [], + "updated_by": [], + "workspace": [], + "project": [], + "initiated_by": [], + "project_detail": [], + "workspace_detail": [], + "service": [], + "status": [], + "metadata": [], + "config": [], + "data": [], + "token": [], + "imported_data": [], + "initiated_by_detail": [ + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ], + }, + ) return Response(serializer.data, status=status.HTTP_201_CREATED) if service == "jira": @@ -213,7 +242,36 @@ class ImportServiceEndpoint(BaseAPIView): ) service_importer.delay(service, importer.id) - serializer = ImporterSerializer(importer) + serializer = ImporterSerializer( + importer, + fields={ + "id": [], + "created_by": [], + "created_at": [], + "updated_at": [], + "updated_by": [], + "workspace": [], + "project": [], + "initiated_by": [], + "project_detail": [], + "workspace_detail": [], + "service": [], + "status": [], + "metadata": [], + "config": [], + "data": [], + "token": [], + "imported_data": [], + "initiated_by_detail": [ + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ], + }, + ) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response( @@ -243,7 +301,39 @@ class ImportServiceEndpoint(BaseAPIView): .order_by("-created_at") .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", + "initiated_by", + "project_detail", + "workspace_detail", + "service", + "status", + "metadata", + "config", + "data", + "token", + "imported_data", + { + "initiated_by_detail": [ + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ] + }, + ], + many=True, + ) return Response(serializer.data) except Exception as e: capture_exception(e) @@ -284,7 +374,40 @@ class ImportServiceEndpoint(BaseAPIView): importer = Importer.objects.get( 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", + "initiated_by", + "project_detail", + "workspace_detail", + "service", + "status", + "metadata", + "config", + "data", + "token", + "imported_data", + { + "initiated_by_detail": [ + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ] + }, + ], + data=request.data, + partial=True, + ) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/apiserver/plane/api/views/inbox.py b/apiserver/plane/api/views/inbox.py index 4fbea5f87..706a2fb22 100644 --- a/apiserver/plane/api/views/inbox.py +++ b/apiserver/plane/api/views/inbox.py @@ -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( issues_data, status=status.HTTP_200_OK, @@ -222,7 +237,19 @@ class InboxIssueViewSet(BaseViewSet): 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) except Exception as e: capture_exception(e) @@ -237,10 +264,17 @@ class InboxIssueViewSet(BaseViewSet): pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id ) # 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 - if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id): - return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST) + if project_member.role <= 10 and str(inbox_issue.created_by_id) != str( + request.user.id + ): + return Response( + {"error": "You cannot edit inbox issues"}, + status=status.HTTP_400_BAD_REQUEST, + ) # Get issue data issue_data = request.data.pop("issue", False) @@ -251,15 +285,29 @@ class InboxIssueViewSet(BaseViewSet): ) # Only allow guests and viewers to edit name and description if project_member.role <= 10: - # viewers and guests since only viewers and guests + # viewers and guests since only viewers and guests issue_data = { "name": issue_data.get("name", issue.name), - "description_html": issue_data.get("description_html", issue.description_html), - "description": issue_data.get("description", issue.description) + "description_html": issue_data.get( + "description_html", issue.description_html + ), + "description": issue_data.get("description", issue.description), } issue_serializer = IssueCreateSerializer( - issue, data=issue_data, partial=True + issue, + data=issue_data, + nested_fields={ + "created_by_detail": ( + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ) + }, + partial=True, ) if issue_serializer.is_valid(): @@ -300,7 +348,9 @@ class InboxIssueViewSet(BaseViewSet): project_id=project_id, ) state = State.objects.filter( - group="cancelled", workspace__slug=slug, project_id=project_id + group="cancelled", + workspace__slug=slug, + project_id=project_id, ).first() if state is not None: issue.state = state @@ -318,7 +368,9 @@ class InboxIssueViewSet(BaseViewSet): if issue.state.name == "Triage": # Move to default state state = State.objects.filter( - workspace__slug=slug, project_id=project_id, default=True + workspace__slug=slug, + project_id=project_id, + default=True, ).first() if state is not None: issue.state = state @@ -327,7 +379,9 @@ class InboxIssueViewSet(BaseViewSet): return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 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: return Response( {"error": "Inbox Issue does not exist"}, @@ -348,7 +402,19 @@ class InboxIssueViewSet(BaseViewSet): issue = Issue.objects.get( 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) except Exception as e: capture_exception(e) @@ -363,15 +429,25 @@ class InboxIssueViewSet(BaseViewSet): pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id ) # 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): - return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST) + if project_member.role <= 10 and str(inbox_issue.created_by_id) != str( + request.user.id + ): + return Response( + {"error": "You cannot delete inbox issue"}, + status=status.HTTP_400_BAD_REQUEST, + ) inbox_issue.delete() return Response(status=status.HTTP_204_NO_CONTENT) 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: capture_exception(e) return Response( @@ -389,7 +465,10 @@ class InboxIssuePublicViewSet(BaseViewSet): ] 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: return self.filter_queryset( super() @@ -407,9 +486,14 @@ class InboxIssuePublicViewSet(BaseViewSet): def list(self, request, slug, project_id, inbox_id): 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: - 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") issues = ( @@ -452,13 +536,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( issues_data, status=status.HTTP_200_OK, ) 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: capture_exception(e) return Response( @@ -468,9 +568,14 @@ class InboxIssuePublicViewSet(BaseViewSet): def create(self, request, slug, project_id, inbox_id): 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: - 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): return Response( @@ -527,7 +632,19 @@ class InboxIssuePublicViewSet(BaseViewSet): 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) except Exception as e: capture_exception(e) @@ -538,33 +655,54 @@ class InboxIssuePublicViewSet(BaseViewSet): def partial_update(self, request, slug, project_id, inbox_id, pk): 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: - 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( pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id ) # Get the project member 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 issue_data = request.data.pop("issue", False) - issue = Issue.objects.get( 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 = { "name": issue_data.get("name", issue.name), - "description_html": issue_data.get("description_html", issue.description_html), - "description": issue_data.get("description", issue.description) + "description_html": issue_data.get( + "description_html", issue.description_html + ), + "description": issue_data.get("description", issue.description), } issue_serializer = IssueCreateSerializer( - issue, data=issue_data, partial=True + issue, + data=issue_data, + nested_fields={ + "created_by_detail": ( + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ) + }, + partial=True, ) if issue_serializer.is_valid(): @@ -600,17 +738,34 @@ class InboxIssuePublicViewSet(BaseViewSet): def retrieve(self, request, slug, project_id, inbox_id, pk): 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: - 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( pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id ) issue = Issue.objects.get( 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) except Exception as e: capture_exception(e) @@ -621,25 +776,35 @@ class InboxIssuePublicViewSet(BaseViewSet): def destroy(self, request, slug, project_id, inbox_id, pk): 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: - 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( pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_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() return Response(status=status.HTTP_204_NO_CONTENT) 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: capture_exception(e) return Response( {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, ) - diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 6f0f1e6ae..ede6fd072 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -281,6 +281,16 @@ class IssueViewSet(BaseViewSet): serializer = IssueCreateSerializer( data=request.data, + nested_fields={ + "created_by_detail": ( + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ) + }, context={ "project_id": project_id, "workspace_id": project.workspace_id, @@ -493,8 +503,34 @@ class IssueActivityEndpoint(BaseAPIView): .order_by("created_at") .select_related("actor", "issue", "project", "workspace") ) - issue_activities = IssueActivitySerializer(issue_activities, many=True).data - issue_comments = IssueCommentSerializer(issue_comments, many=True).data + issue_activities = IssueActivitySerializer( + 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( chain(issue_activities, issue_comments), @@ -522,6 +558,9 @@ class IssueCommentViewSet(BaseViewSet): "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): serializer.save( project_id=self.kwargs.get("project_id"), @@ -550,7 +589,19 @@ class IssueCommentViewSet(BaseViewSet): issue_id=str(self.kwargs.get("issue_id", None)), project_id=str(self.kwargs.get("project_id", None)), 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, ), ) @@ -571,7 +622,19 @@ class IssueCommentViewSet(BaseViewSet): issue_id=str(self.kwargs.get("issue_id", None)), project_id=str(self.kwargs.get("project_id", None)), 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, ), ) @@ -769,7 +832,9 @@ class SubIssuesEndpoint(BaseAPIView): .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( sub_issues, @@ -1507,7 +1572,19 @@ class IssueCommentPublicViewSet(BaseViewSet): 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(): serializer.save( project_id=project_id, @@ -1547,7 +1624,19 @@ class IssueCommentPublicViewSet(BaseViewSet): workspace__slug=slug, pk=pk, actor=request.user ) 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(): serializer.save() @@ -1558,7 +1647,19 @@ class IssueCommentPublicViewSet(BaseViewSet): issue_id=str(issue_id), project_id=str(project_id), 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, ), ) @@ -1567,7 +1668,8 @@ class IssueCommentPublicViewSet(BaseViewSet): except (IssueComment.DoesNotExist, ProjectDeployBoard.DoesNotExist): return Response( {"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): try: @@ -1590,7 +1692,19 @@ class IssueCommentPublicViewSet(BaseViewSet): issue_id=str(issue_id), project_id=str(project_id), 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, ), ) @@ -1835,9 +1949,11 @@ class ExportIssuesEndpoint(BaseAPIView): def post(self, request, slug): try: - 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( @@ -1851,4 +1967,4 @@ class ExportIssuesEndpoint(BaseAPIView): return Response( {"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST, - ) \ No newline at end of file + ) diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 6adee0016..13a79cafd 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -91,10 +91,10 @@ class ProjectViewSet(BaseViewSet): ProjectBasePermission, ] - def get_serializer_class(self, *args, **kwargs): - if self.action == "update" or self.action == "partial_update": - return ProjectSerializer - return ProjectDetailSerializer + # def get_serializer_class(self, *args, **kwargs): + # if self.action == "update" or self.action == "partial_update": + # 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 def get_queryset(self): subquery = ProjectFavorite.objects.filter( @@ -216,7 +216,38 @@ class ProjectViewSet(BaseViewSet): workspace = Workspace.objects.get(slug=slug) 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(): serializer.save() @@ -330,6 +361,36 @@ class ProjectViewSet(BaseViewSet): serializer = ProjectSerializer( project, 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}, partial=True, ) @@ -1263,7 +1324,7 @@ class ProjectDeployBoardIssuesPublicEndpoint(BaseAPIView): workspace__slug=slug, project_id=project_id ).values("id", "name", "color", "parent") - ## Grouping the results + # Grouping the results group_by = request.GET.get("group_by", False) if group_by: issues = group_results(issues, group_by) diff --git a/apiserver/plane/api/views/user.py b/apiserver/plane/api/views/user.py index 84ee47e42..57e0c610e 100644 --- a/apiserver/plane/api/views/user.py +++ b/apiserver/plane/api/views/user.py @@ -147,7 +147,18 @@ class UserActivityEndpoint(BaseAPIView, BasePaginator): request=request, queryset=queryset, 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, ) except Exception as e: diff --git a/apiserver/plane/api/views/workspace.py b/apiserver/plane/api/views/workspace.py index fd79c226a..15ab23e47 100644 --- a/apiserver/plane/api/views/workspace.py +++ b/apiserver/plane/api/views/workspace.py @@ -163,8 +163,8 @@ class WorkSpaceViewSet(BaseViewSet): status=status.HTTP_400_BAD_REQUEST, ) - ## Handling unique integrity error for now - ## TODO: Extend this to handle other common errors which are not automatically handled by APIException + # Handling unique integrity error for now + # TODO: Extend this to handle other common errors which are not automatically handled by APIException except IntegrityError as e: if "already exists" in str(e): return Response( @@ -299,7 +299,31 @@ class InviteWorkspaceEndpoint(BaseAPIView): { "error": "Some users are already member of workspace", "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, }, status=status.HTTP_400_BAD_REQUEST, @@ -541,7 +565,7 @@ class UserWorkspaceInvitationsEndpoint(BaseViewSet): class WorkSpaceMemberViewSet(BaseViewSet): - # serializer_class = WorkSpaceMemberSerializer + serializer_class = WorkSpaceMemberSerializer model = WorkspaceMember permission_classes = [ @@ -590,7 +614,32 @@ class WorkSpaceMemberViewSet(BaseViewSet): ) 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(): @@ -724,7 +773,18 @@ class TeamMemberViewSet(BaseViewSet): users = list(set(request.data.get("members", [])).difference(members)) users = User.objects.filter(pk__in=users) - serializer = UserSerializer(users, fields=('id', 'first_name',"last_name","avatar","is_bot","display_name"),many=True) + serializer = UserSerializer( + users, + fields=[ + "id", + "first_name", + "last_name", + "avatar", + "is_bot", + "display_name", + ], + many=True, + ) return Response( { "error": f"{len(users)} of the member(s) are not a part of the workspace", @@ -790,15 +850,95 @@ class UserLastProjectWithWorkspaceEndpoint(BaseAPIView): ) workspace = Workspace.objects.get(pk=last_workspace_id) - workspace_serializer = WorkSpaceSerializer(workspace) - # workspace_serializer = WorkSpaceSerializer(workspace, fields=("member": (fields: "displayname"))) + 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( workspace_id=last_workspace_id, member=request.user ).select_related("workspace", "project", "member", "workspace__owner") 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( @@ -825,7 +965,32 @@ class WorkspaceMemberUserEndpoint(BaseAPIView): workspace_member = WorkspaceMember.objects.get( member=request.user, workspace__slug=slug ) - serializer = WorkSpaceMemberSerializer(workspace_member, fields=("member","workspace"), remove_nested_fields={"member": ("email",)}) + 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) except (Workspace.DoesNotExist, WorkspaceMember.DoesNotExist): return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN) @@ -998,7 +1163,7 @@ class UserWorkspaceDashboardEndpoint(BaseAPIView): workspace__slug=slug, assignees__in=[request.user], completed_at__isnull=True, - ).values("id", "name", "workspace__slug", "project_id", "target_date") + ).values("id", "name", "workspace__slug", "project_id", "start_date") return Response( { @@ -1209,7 +1374,18 @@ class WorkspaceUserActivityEndpoint(BaseAPIView): request=request, queryset=queryset, 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, ) except Exception as e: @@ -1417,7 +1593,7 @@ class WorkspaceUserProfileIssuesEndpoint(BaseAPIView): issues = IssueLiteSerializer(issue_queryset, many=True).data - ## Grouping the results + # Grouping the results group_by = request.GET.get("group_by", False) if group_by: return Response( @@ -1464,8 +1640,34 @@ class WorkspaceMembersEndpoint(BaseAPIView): workspace__slug=slug, member__is_bot=False, ).select_related("workspace", "member") - serialzier = WorkSpaceMemberSerializer(workspace_members, many=True) - return Response(serialzier.data, status=status.HTTP_200_OK) + serializer = WorkSpaceMemberSerializer( + 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: capture_exception(e) return Response( diff --git a/apiserver/plane/bgtasks/importer_task.py b/apiserver/plane/bgtasks/importer_task.py index 757ef601b..0798913d2 100644 --- a/apiserver/plane/bgtasks/importer_task.py +++ b/apiserver/plane/bgtasks/importer_task.py @@ -161,7 +161,7 @@ def service_importer(service, importer_id): if settings.PROXY_BASE_URL: headers = {"Content-Type": "application/json"} import_data_json = json.dumps( - ImporterSerializer(importer).data, + ImporterSerializer(importer,fields=["id","created_by","created_at","updated_at","updated_by","workspace","project","initiated_by","project_detail","workspace_detail","service","status","metadata","config","data","token","imported_data",{"initiated_by_detail":["id", "first_name", "last_name", "avatar", "is_bot", "display_name"]}]).data, cls=DjangoJSONEncoder, ) res = requests.post( diff --git a/apiserver/plane/bgtasks/issue_activites_task.py b/apiserver/plane/bgtasks/issue_activites_task.py index 1cc6c85cc..ed82f02af 100644 --- a/apiserver/plane/bgtasks/issue_activites_task.py +++ b/apiserver/plane/bgtasks/issue_activites_task.py @@ -1103,7 +1103,7 @@ def issue_activity( for issue_activity in issue_activities_created: headers = {"Content-Type": "application/json"} 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, ) _ = requests.post(