diff --git a/apiserver/plane/api/serializers/__init__.py b/apiserver/plane/api/serializers/__init__.py index 263be85b85d..1f17e053e0c 100644 --- a/apiserver/plane/api/serializers/__init__.py +++ b/apiserver/plane/api/serializers/__init__.py @@ -18,4 +18,4 @@ ModuleIssueSerializer, ModuleLiteSerializer, ) -from .inbox import InboxIssueSerializer +from .intake import IntakeIssueSerializer diff --git a/apiserver/plane/api/serializers/inbox.py b/apiserver/plane/api/serializers/intake.py similarity index 66% rename from apiserver/plane/api/serializers/inbox.py rename to apiserver/plane/api/serializers/intake.py index a0c79235df2..0b207c704d7 100644 --- a/apiserver/plane/api/serializers/inbox.py +++ b/apiserver/plane/api/serializers/intake.py @@ -1,15 +1,17 @@ # Module improts from .base import BaseSerializer from .issue import IssueExpandSerializer -from plane.db.models import InboxIssue +from plane.db.models import IntakeIssue +from rest_framework import serializers -class InboxIssueSerializer(BaseSerializer): +class IntakeIssueSerializer(BaseSerializer): issue_detail = IssueExpandSerializer(read_only=True, source="issue") + inbox = serializers.UUIDField(source="intake.id", read_only=True) class Meta: - model = InboxIssue + model = IntakeIssue fields = "__all__" read_only_fields = [ "id", diff --git a/apiserver/plane/api/serializers/project.py b/apiserver/plane/api/serializers/project.py index 591a1203dcc..d9c3e2c2a98 100644 --- a/apiserver/plane/api/serializers/project.py +++ b/apiserver/plane/api/serializers/project.py @@ -20,6 +20,7 @@ class ProjectSerializer(BaseSerializer): member_role = serializers.IntegerField(read_only=True) is_deployed = serializers.BooleanField(read_only=True) cover_image_url = serializers.CharField(read_only=True) + inbox_view = serializers.BooleanField(read_only=True, source="intake_view") class Meta: model = Project diff --git a/apiserver/plane/api/urls/__init__.py b/apiserver/plane/api/urls/__init__.py index efa84bce038..d9b55e20e12 100644 --- a/apiserver/plane/api/urls/__init__.py +++ b/apiserver/plane/api/urls/__init__.py @@ -3,7 +3,7 @@ from .issue import urlpatterns as issue_patterns from .cycle import urlpatterns as cycle_patterns from .module import urlpatterns as module_patterns -from .inbox import urlpatterns as inbox_patterns +from .intake import urlpatterns as intake_patterns from .member import urlpatterns as member_patterns urlpatterns = [ @@ -12,6 +12,6 @@ *issue_patterns, *cycle_patterns, *module_patterns, - *inbox_patterns, + *intake_patterns, *member_patterns, ] diff --git a/apiserver/plane/api/urls/inbox.py b/apiserver/plane/api/urls/inbox.py deleted file mode 100644 index 95eb68f3f2b..00000000000 --- a/apiserver/plane/api/urls/inbox.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.urls import path - -from plane.api.views import InboxIssueAPIEndpoint - - -urlpatterns = [ - path( - "workspaces//projects//inbox-issues/", - InboxIssueAPIEndpoint.as_view(), - name="inbox-issue", - ), - path( - "workspaces//projects//inbox-issues//", - InboxIssueAPIEndpoint.as_view(), - name="inbox-issue", - ), -] diff --git a/apiserver/plane/api/urls/intake.py b/apiserver/plane/api/urls/intake.py new file mode 100644 index 00000000000..a47d010eef9 --- /dev/null +++ b/apiserver/plane/api/urls/intake.py @@ -0,0 +1,27 @@ +from django.urls import path + +from plane.api.views import IntakeIssueAPIEndpoint + + +urlpatterns = [ + path( + "workspaces//projects//inbox-issues/", + IntakeIssueAPIEndpoint.as_view(), + name="inbox-issue", + ), + path( + "workspaces//projects//inbox-issues//", + IntakeIssueAPIEndpoint.as_view(), + name="inbox-issue", + ), + path( + "workspaces//projects//intake-issues/", + IntakeIssueAPIEndpoint.as_view(), + name="intake-issue", + ), + path( + "workspaces//projects//intake-issues//", + IntakeIssueAPIEndpoint.as_view(), + name="intake-issue", + ), +] diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index bbec428c053..2299f7ec5b9 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -27,5 +27,4 @@ from .member import ProjectMemberAPIEndpoint -from .inbox import InboxIssueAPIEndpoint - +from .intake import IntakeIssueAPIEndpoint diff --git a/apiserver/plane/api/views/inbox.py b/apiserver/plane/api/views/intake.py similarity index 80% rename from apiserver/plane/api/views/inbox.py rename to apiserver/plane/api/views/intake.py index 381e12aab07..95354f2359f 100644 --- a/apiserver/plane/api/views/inbox.py +++ b/apiserver/plane/api/views/intake.py @@ -14,12 +14,12 @@ from rest_framework.response import Response # Module imports -from plane.api.serializers import InboxIssueSerializer, IssueSerializer +from plane.api.serializers import IntakeIssueSerializer, IssueSerializer from plane.app.permissions import ProjectLitePermission from plane.bgtasks.issue_activities_task import issue_activity from plane.db.models import ( - Inbox, - InboxIssue, + Intake, + IntakeIssue, Issue, Project, ProjectMember, @@ -29,10 +29,10 @@ from .base import BaseAPIView -class InboxIssueAPIEndpoint(BaseAPIView): +class IntakeIssueAPIEndpoint(BaseAPIView): """ This viewset automatically provides `list`, `create`, `retrieve`, - `update` and `destroy` actions related to inbox issues. + `update` and `destroy` actions related to intake issues. """ @@ -40,15 +40,15 @@ class InboxIssueAPIEndpoint(BaseAPIView): ProjectLitePermission, ] - serializer_class = InboxIssueSerializer - model = InboxIssue + serializer_class = IntakeIssueSerializer + model = IntakeIssue filterset_fields = [ "status", ] def get_queryset(self): - inbox = Inbox.objects.filter( + intake = Intake.objects.filter( workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), ).first() @@ -58,16 +58,16 @@ def get_queryset(self): pk=self.kwargs.get("project_id"), ) - if inbox is None and not project.inbox_view: - return InboxIssue.objects.none() + if intake is None and not project.intake_view: + return IntakeIssue.objects.none() return ( - InboxIssue.objects.filter( + IntakeIssue.objects.filter( Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True), workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"), - inbox_id=inbox.id, + intake_id=intake.id, ) .select_related("issue", "workspace", "project") .order_by(self.kwargs.get("order_by", "-created_at")) @@ -75,22 +75,22 @@ def get_queryset(self): def get(self, request, slug, project_id, issue_id=None): if issue_id: - inbox_issue_queryset = self.get_queryset().get(issue_id=issue_id) - inbox_issue_data = InboxIssueSerializer( - inbox_issue_queryset, + intake_issue_queryset = self.get_queryset().get(issue_id=issue_id) + intake_issue_data = IntakeIssueSerializer( + intake_issue_queryset, fields=self.fields, expand=self.expand, ).data return Response( - inbox_issue_data, + intake_issue_data, status=status.HTTP_200_OK, ) issue_queryset = self.get_queryset() return self.paginate( request=request, queryset=(issue_queryset), - on_results=lambda inbox_issues: InboxIssueSerializer( - inbox_issues, + on_results=lambda intake_issues: IntakeIssueSerializer( + intake_issues, many=True, fields=self.fields, expand=self.expand, @@ -104,7 +104,7 @@ def post(self, request, slug, project_id): status=status.HTTP_400_BAD_REQUEST, ) - inbox = Inbox.objects.filter( + intake = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() @@ -113,11 +113,11 @@ def post(self, request, slug, project_id): pk=project_id, ) - # Inbox view - if inbox is None and not project.inbox_view: + # Intake view + if intake is None and not project.intake_view: return Response( { - "error": "Inbox is not enabled for this project enable it through the project's api" + "error": "Intake is not enabled for this project enable it through the project's api" }, status=status.HTTP_400_BAD_REQUEST, ) @@ -139,7 +139,7 @@ def post(self, request, slug, project_id): state, _ = State.objects.get_or_create( name="Triage", group="triage", - description="Default state for managing all Inbox Issues", + description="Default state for managing all Intake Issues", project_id=project_id, color="#ff7700", is_triage=True, @@ -157,12 +157,12 @@ def post(self, request, slug, project_id): state=state, ) - # create an inbox issue - inbox_issue = InboxIssue.objects.create( - inbox_id=inbox.id, + # create an intake issue + intake_issue = IntakeIssue.objects.create( + intake_id=intake.id, project_id=project_id, issue=issue, - source=request.data.get("source", "in-app"), + source=request.data.get("source", "IN-APP"), ) # Create an Issue Activity issue_activity.delay( @@ -173,32 +173,37 @@ def post(self, request, slug, project_id): project_id=str(project_id), current_instance=None, epoch=int(timezone.now().timestamp()), - inbox=str(inbox_issue.id), + intake=str(intake_issue.id), ) - serializer = InboxIssueSerializer(inbox_issue) + serializer = IntakeIssueSerializer(intake_issue) return Response(serializer.data, status=status.HTTP_200_OK) def patch(self, request, slug, project_id, issue_id): - inbox = Inbox.objects.filter( + intake = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() - # Inbox view - if inbox is None: + project = Project.objects.get( + workspace__slug=slug, + pk=project_id, + ) + + # Intake view + if intake is None and not project.intake_view: return Response( { - "error": "Inbox is not enabled for this project enable it through the project's api" + "error": "Intake is not enabled for this project enable it through the project's api" }, status=status.HTTP_400_BAD_REQUEST, ) - # Get the inbox issue - inbox_issue = InboxIssue.objects.get( + # Get the intake issue + intake_issue = IntakeIssue.objects.get( issue_id=issue_id, workspace__slug=slug, project_id=project_id, - inbox_id=inbox.id, + intake_id=intake.id, ) # Get the project member @@ -210,11 +215,11 @@ def patch(self, request, slug, project_id, issue_id): ) # Only project members admins and created_by users can access this endpoint - if project_member.role <= 5 and str(inbox_issue.created_by_id) != str( + if project_member.role <= 5 and str(intake_issue.created_by_id) != str( request.user.id ): return Response( - {"error": "You cannot edit inbox issues"}, + {"error": "You cannot edit intake issues"}, status=status.HTTP_400_BAD_REQUEST, ) @@ -283,7 +288,7 @@ def patch(self, request, slug, project_id, issue_id): cls=DjangoJSONEncoder, ), epoch=int(timezone.now().timestamp()), - inbox=(inbox_issue.id), + intake=(intake_issue.id), ) issue_serializer.save() else: @@ -291,13 +296,13 @@ def patch(self, request, slug, project_id, issue_id): issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST ) - # Only project admins and members can edit inbox issue attributes + # Only project admins and members can edit intake issue attributes if project_member.role > 15: - serializer = InboxIssueSerializer( - inbox_issue, data=request.data, partial=True + serializer = IntakeIssueSerializer( + intake_issue, data=request.data, partial=True ) current_instance = json.dumps( - InboxIssueSerializer(inbox_issue).data, cls=DjangoJSONEncoder + IntakeIssueSerializer(intake_issue).data, cls=DjangoJSONEncoder ) if serializer.is_valid(): @@ -340,7 +345,7 @@ def patch(self, request, slug, project_id, issue_id): # create a activity for status change issue_activity.delay( - type="inbox.activity.created", + type="intake.activity.created", requested_data=json.dumps( request.data, cls=DjangoJSONEncoder ), @@ -351,7 +356,7 @@ def patch(self, request, slug, project_id, issue_id): epoch=int(timezone.now().timestamp()), notification=False, origin=request.META.get("HTTP_ORIGIN"), - inbox=str(inbox_issue.id), + intake=str(intake_issue.id), ) return Response(serializer.data, status=status.HTTP_200_OK) @@ -360,12 +365,12 @@ def patch(self, request, slug, project_id, issue_id): ) else: return Response( - InboxIssueSerializer(inbox_issue).data, + IntakeIssueSerializer(intake_issue).data, status=status.HTTP_200_OK, ) def delete(self, request, slug, project_id, issue_id): - inbox = Inbox.objects.filter( + intake = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() @@ -374,25 +379,25 @@ def delete(self, request, slug, project_id, issue_id): pk=project_id, ) - # Inbox view - if inbox is None and not project.inbox_view: + # Intake view + if intake is None and not project.intake_view: return Response( { - "error": "Inbox is not enabled for this project enable it through the project's api" + "error": "Intake is not enabled for this project enable it through the project's api" }, status=status.HTTP_400_BAD_REQUEST, ) - # Get the inbox issue - inbox_issue = InboxIssue.objects.get( + # Get the intake issue + intake_issue = IntakeIssue.objects.get( issue_id=issue_id, workspace__slug=slug, project_id=project_id, - inbox_id=inbox.id, + intake_id=intake.id, ) # Check the issue status - if inbox_issue.status in [-2, -1, 0, 2]: + if intake_issue.status in [-2, -1, 0, 2]: # Delete the issue also issue = Issue.objects.filter( workspace__slug=slug, project_id=project_id, pk=issue_id @@ -412,5 +417,5 @@ def delete(self, request, slug, project_id, issue_id): ) issue.delete() - inbox_issue.delete() + intake_issue.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 594329a44af..92a924e11bb 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -18,7 +18,7 @@ # Module imports from plane.db.models import ( Cycle, - Inbox, + Intake, IssueUserProperty, Module, Project, @@ -285,6 +285,11 @@ def patch(self, request, slug, pk): current_instance = json.dumps( ProjectSerializer(project).data, cls=DjangoJSONEncoder ) + + intake_view = request.data.get( + "inbox_view", request.data.get("intake_view", False) + ) + if project.archived_at: return Response( {"error": "Archived project cannot be updated"}, @@ -293,21 +298,24 @@ def patch(self, request, slug, pk): serializer = ProjectSerializer( project, - data={**request.data}, + data={ + **request.data, + "intake_view": intake_view, + }, context={"workspace_id": workspace.id}, partial=True, ) if serializer.is_valid(): serializer.save() - if serializer.data["inbox_view"]: - inbox = Inbox.objects.filter( + if serializer.data["intake_view"]: + intake = Intake.objects.filter( project=project, is_default=True, ).first() - if not inbox: - Inbox.objects.create( - name=f"{project.name} Inbox", + if not intake: + Intake.objects.create( + name=f"{project.name} Intake", project=project, is_default=True, ) @@ -316,7 +324,7 @@ def patch(self, request, slug, pk): State.objects.get_or_create( name="Triage", group="triage", - description="Default state for managing all Inbox Issues", + description="Default state for managing all Intake Issues", project_id=pk, color="#ff7700", is_triage=True, diff --git a/apiserver/plane/app/serializers/__init__.py b/apiserver/plane/app/serializers/__init__.py index b3c3d794994..2e2c91baa1f 100644 --- a/apiserver/plane/app/serializers/__init__.py +++ b/apiserver/plane/app/serializers/__init__.py @@ -57,7 +57,7 @@ IssueFlatSerializer, IssueStateSerializer, IssueLinkSerializer, - IssueInboxSerializer, + IssueIntakeSerializer, IssueLiteSerializer, IssueAttachmentSerializer, IssueSubscriberSerializer, @@ -102,12 +102,12 @@ WorkspaceEstimateSerializer, ) -from .inbox import ( - InboxSerializer, - InboxIssueSerializer, - IssueStateInboxSerializer, - InboxIssueLiteSerializer, - InboxIssueDetailSerializer, +from .intake import ( + IntakeSerializer, + IntakeIssueSerializer, + IssueStateIntakeSerializer, + IntakeIssueLiteSerializer, + IntakeIssueDetailSerializer, ) from .analytic import AnalyticViewSerializer diff --git a/apiserver/plane/app/serializers/base.py b/apiserver/plane/app/serializers/base.py index 10260de5830..ed320104356 100644 --- a/apiserver/plane/app/serializers/base.py +++ b/apiserver/plane/app/serializers/base.py @@ -60,7 +60,7 @@ def _filter_fields(self, fields): CycleIssueSerializer, IssueLiteSerializer, IssueRelationSerializer, - InboxIssueLiteSerializer, + IntakeIssueLiteSerializer, IssueReactionLiteSerializer, IssueLinkLiteSerializer, RelatedIssueSerializer, @@ -84,8 +84,8 @@ def _filter_fields(self, fields): "issue_cycle": CycleIssueSerializer, "parent": IssueLiteSerializer, "issue_relation": IssueRelationSerializer, + "issue_intake": IntakeIssueLiteSerializer, "issue_related": RelatedIssueSerializer, - "issue_inbox": InboxIssueLiteSerializer, "issue_reactions": IssueReactionLiteSerializer, "issue_link": IssueLinkLiteSerializer, "sub_issues": IssueLiteSerializer, @@ -102,7 +102,7 @@ def _filter_fields(self, fields): "labels", "issue_cycle", "issue_relation", - "issue_inbox", + "issue_intake", "issue_reactions", "issue_attachment", "issue_link", @@ -132,7 +132,7 @@ def to_representation(self, instance): LabelSerializer, CycleIssueSerializer, IssueRelationSerializer, - InboxIssueLiteSerializer, + IntakeIssueLiteSerializer, IssueLiteSerializer, IssueReactionLiteSerializer, IssueAttachmentLiteSerializer, @@ -158,8 +158,8 @@ def to_representation(self, instance): "issue_cycle": CycleIssueSerializer, "parent": IssueLiteSerializer, "issue_relation": IssueRelationSerializer, + "issue_intake": IntakeIssueLiteSerializer, "issue_related": RelatedIssueSerializer, - "issue_inbox": InboxIssueLiteSerializer, "issue_reactions": IssueReactionLiteSerializer, "issue_attachment": IssueAttachmentLiteSerializer, "issue_link": IssueLinkLiteSerializer, diff --git a/apiserver/plane/app/serializers/inbox.py b/apiserver/plane/app/serializers/intake.py similarity index 81% rename from apiserver/plane/app/serializers/inbox.py rename to apiserver/plane/app/serializers/intake.py index e0c18b3d1b5..3800b13ab9b 100644 --- a/apiserver/plane/app/serializers/inbox.py +++ b/apiserver/plane/app/serializers/intake.py @@ -4,22 +4,22 @@ # Module imports from .base import BaseSerializer from .issue import ( - IssueInboxSerializer, + IssueIntakeSerializer, LabelLiteSerializer, IssueDetailSerializer, ) from .project import ProjectLiteSerializer from .state import StateLiteSerializer from .user import UserLiteSerializer -from plane.db.models import Inbox, InboxIssue, Issue +from plane.db.models import Intake, IntakeIssue, Issue -class InboxSerializer(BaseSerializer): +class IntakeSerializer(BaseSerializer): project_detail = ProjectLiteSerializer(source="project", read_only=True) pending_issue_count = serializers.IntegerField(read_only=True) class Meta: - model = Inbox + model = Intake fields = "__all__" read_only_fields = [ "project", @@ -27,11 +27,11 @@ class Meta: ] -class InboxIssueSerializer(BaseSerializer): - issue = IssueInboxSerializer(read_only=True) +class IntakeIssueSerializer(BaseSerializer): + issue = IssueIntakeSerializer(read_only=True) class Meta: - model = InboxIssue + model = IntakeIssue fields = [ "id", "status", @@ -53,14 +53,14 @@ def to_representation(self, instance): return super().to_representation(instance) -class InboxIssueDetailSerializer(BaseSerializer): +class IntakeIssueDetailSerializer(BaseSerializer): issue = IssueDetailSerializer(read_only=True) - duplicate_issue_detail = IssueInboxSerializer( + duplicate_issue_detail = IssueIntakeSerializer( read_only=True, source="duplicate_to" ) class Meta: - model = InboxIssue + model = IntakeIssue fields = [ "id", "status", @@ -85,14 +85,14 @@ def to_representation(self, instance): return super().to_representation(instance) -class InboxIssueLiteSerializer(BaseSerializer): +class IntakeIssueLiteSerializer(BaseSerializer): class Meta: - model = InboxIssue + model = IntakeIssue fields = ["id", "status", "duplicate_to", "snoozed_till", "source"] read_only_fields = fields -class IssueStateInboxSerializer(BaseSerializer): +class IssueStateIntakeSerializer(BaseSerializer): state_detail = StateLiteSerializer(read_only=True, source="state") project_detail = ProjectLiteSerializer(read_only=True, source="project") label_details = LabelLiteSerializer( @@ -102,7 +102,7 @@ class IssueStateInboxSerializer(BaseSerializer): read_only=True, source="assignees", many=True ) sub_issues_count = serializers.IntegerField(read_only=True) - issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True) + issue_intake = IntakeIssueLiteSerializer(read_only=True, many=True) class Meta: model = Issue diff --git a/apiserver/plane/app/serializers/issue.py b/apiserver/plane/app/serializers/issue.py index 2323c248a86..9439c906c75 100644 --- a/apiserver/plane/app/serializers/issue.py +++ b/apiserver/plane/app/serializers/issue.py @@ -643,7 +643,7 @@ class Meta: fields = "__all__" -class IssueInboxSerializer(DynamicBaseSerializer): +class IssueIntakeSerializer(DynamicBaseSerializer): label_ids = serializers.ListField( child=serializers.UUIDField(), required=False, diff --git a/apiserver/plane/app/serializers/notification.py b/apiserver/plane/app/serializers/notification.py index a99b63e0db9..2f79992f2bf 100644 --- a/apiserver/plane/app/serializers/notification.py +++ b/apiserver/plane/app/serializers/notification.py @@ -12,6 +12,7 @@ class NotificationSerializer(BaseSerializer): read_only=True, source="triggered_by" ) is_inbox_issue = serializers.BooleanField(read_only=True) + is_intake_issue = serializers.BooleanField(read_only=True) is_mentioned_notification = serializers.BooleanField(read_only=True) class Meta: diff --git a/apiserver/plane/app/serializers/project.py b/apiserver/plane/app/serializers/project.py index 24bc5464e16..ccf9251bced 100644 --- a/apiserver/plane/app/serializers/project.py +++ b/apiserver/plane/app/serializers/project.py @@ -22,6 +22,7 @@ class ProjectSerializer(BaseSerializer): workspace_detail = WorkspaceLiteSerializer( source="workspace", read_only=True ) + inbox_view = serializers.BooleanField(read_only=True, source="intake_view") class Meta: model = Project @@ -119,6 +120,7 @@ class ProjectListSerializer(DynamicBaseSerializer): anchor = serializers.CharField(read_only=True) members = serializers.SerializerMethodField() cover_image_url = serializers.CharField(read_only=True) + inbox_view = serializers.BooleanField(read_only=True, source="intake_view") def get_members(self, obj): project_members = getattr(obj, "members_list", None) diff --git a/apiserver/plane/app/urls/__init__.py b/apiserver/plane/app/urls/__init__.py index cb5f0253adc..8798e80440e 100644 --- a/apiserver/plane/app/urls/__init__.py +++ b/apiserver/plane/app/urls/__init__.py @@ -5,7 +5,7 @@ from .dashboard import urlpatterns as dashboard_urls from .estimate import urlpatterns as estimate_urls from .external import urlpatterns as external_urls -from .inbox import urlpatterns as inbox_urls +from .intake import urlpatterns as intake_urls from .issue import urlpatterns as issue_urls from .module import urlpatterns as module_urls from .notification import urlpatterns as notification_urls @@ -25,7 +25,7 @@ *dashboard_urls, *estimate_urls, *external_urls, - *inbox_urls, + *intake_urls, *issue_urls, *module_urls, *notification_urls, diff --git a/apiserver/plane/app/urls/inbox.py b/apiserver/plane/app/urls/inbox.py deleted file mode 100644 index 6508c001d3a..00000000000 --- a/apiserver/plane/app/urls/inbox.py +++ /dev/null @@ -1,53 +0,0 @@ -from django.urls import path - - -from plane.app.views import ( - InboxViewSet, - InboxIssueViewSet, -) - - -urlpatterns = [ - path( - "workspaces//projects//inboxes/", - InboxViewSet.as_view( - { - "get": "list", - "post": "create", - } - ), - name="inbox", - ), - path( - "workspaces//projects//inboxes//", - InboxViewSet.as_view( - { - "get": "retrieve", - "patch": "partial_update", - "delete": "destroy", - } - ), - name="inbox", - ), - path( - "workspaces//projects//inbox-issues/", - InboxIssueViewSet.as_view( - { - "get": "list", - "post": "create", - } - ), - name="inbox-issue", - ), - path( - "workspaces//projects//inbox-issues//", - InboxIssueViewSet.as_view( - { - "get": "retrieve", - "patch": "partial_update", - "delete": "destroy", - } - ), - name="inbox-issue", - ), -] diff --git a/apiserver/plane/app/urls/intake.py b/apiserver/plane/app/urls/intake.py new file mode 100644 index 00000000000..be2f3a053f4 --- /dev/null +++ b/apiserver/plane/app/urls/intake.py @@ -0,0 +1,95 @@ +from django.urls import path + + +from plane.app.views import ( + IntakeViewSet, + IntakeIssueViewSet, +) + + +urlpatterns = [ + path( + "workspaces//projects//intakes/", + IntakeViewSet.as_view( + { + "get": "list", + "post": "create", + } + ), + name="intake", + ), + path( + "workspaces//projects//intakes//", + IntakeViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + "delete": "destroy", + } + ), + name="intake", + ), + path( + "workspaces//projects//intake-issues/", + IntakeIssueViewSet.as_view( + { + "get": "list", + "post": "create", + } + ), + name="intake-issue", + ), + path( + "workspaces//projects//intake-issues//", + IntakeIssueViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + "delete": "destroy", + } + ), + name="intake-issue", + ), + path( + "workspaces//projects//inboxes/", + IntakeViewSet.as_view( + { + "get": "list", + "post": "create", + } + ), + name="inbox", + ), + path( + "workspaces//projects//inboxes//", + IntakeViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + "delete": "destroy", + } + ), + name="inbox", + ), + path( + "workspaces//projects//inbox-issues/", + IntakeIssueViewSet.as_view( + { + "get": "list", + "post": "create", + } + ), + name="inbox-issue", + ), + path( + "workspaces//projects//inbox-issues//", + IntakeIssueViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + "delete": "destroy", + } + ), + name="inbox-issue", + ), +] diff --git a/apiserver/plane/app/views/__init__.py b/apiserver/plane/app/views/__init__.py index 1f94cb7ac9a..159686fa3ac 100644 --- a/apiserver/plane/app/views/__init__.py +++ b/apiserver/plane/app/views/__init__.py @@ -220,7 +220,7 @@ EstimatePointEndpoint, ) -from .inbox.base import InboxViewSet, InboxIssueViewSet +from .intake.base import IntakeViewSet, IntakeIssueViewSet from .analytic.base import ( AnalyticsEndpoint, diff --git a/apiserver/plane/app/views/cycle/issue.py b/apiserver/plane/app/views/cycle/issue.py index de11a0b707a..6066d9045b5 100644 --- a/apiserver/plane/app/views/cycle/issue.py +++ b/apiserver/plane/app/views/cycle/issue.py @@ -12,6 +12,7 @@ from rest_framework import status from rest_framework.response import Response + # Module imports from .. import BaseViewSet from plane.app.serializers import ( @@ -39,6 +40,7 @@ from plane.app.permissions import allow_permission, ROLE + class CycleIssueViewSet(BaseViewSet): serializer_class = CycleIssueSerializer model = CycleIssue @@ -194,10 +196,10 @@ def list(self, request, slug, project_id, cycle_id): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -223,10 +225,10 @@ def list(self, request, slug, project_id, cycle_id): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/app/views/inbox/base.py b/apiserver/plane/app/views/intake/base.py similarity index 84% rename from apiserver/plane/app/views/inbox/base.py rename to apiserver/plane/app/views/intake/base.py index 3654df38ea2..9e420c00720 100644 --- a/apiserver/plane/app/views/inbox/base.py +++ b/apiserver/plane/app/views/intake/base.py @@ -18,8 +18,8 @@ from ..base import BaseViewSet from plane.app.permissions import allow_permission, ROLE from plane.db.models import ( - Inbox, - InboxIssue, + Intake, + IntakeIssue, Issue, State, IssueLink, @@ -31,18 +31,18 @@ from plane.app.serializers import ( IssueCreateSerializer, IssueSerializer, - InboxSerializer, - InboxIssueSerializer, - InboxIssueDetailSerializer, + IntakeSerializer, + IntakeIssueSerializer, + IntakeIssueDetailSerializer, ) from plane.utils.issue_filters import issue_filters from plane.bgtasks.issue_activities_task import issue_activity -class InboxViewSet(BaseViewSet): +class IntakeViewSet(BaseViewSet): - serializer_class = InboxSerializer - model = Inbox + serializer_class = IntakeSerializer + model = Intake def get_queryset(self): return ( @@ -54,8 +54,8 @@ def get_queryset(self): ) .annotate( pending_issue_count=Count( - "issue_inbox", - filter=Q(issue_inbox__status=-2), + "issue_intake", + filter=Q(issue_intake__status=-2), ) ) .select_related("workspace", "project") @@ -63,9 +63,9 @@ def get_queryset(self): @allow_permission([ROLE.ADMIN, ROLE.MEMBER]) def list(self, request, slug, project_id): - inbox = self.get_queryset().first() + intake = self.get_queryset().first() return Response( - InboxSerializer(inbox).data, + IntakeSerializer(intake).data, status=status.HTTP_200_OK, ) @@ -75,26 +75,26 @@ def perform_create(self, serializer): @allow_permission([ROLE.ADMIN, ROLE.MEMBER]) def destroy(self, request, slug, project_id, pk): - inbox = Inbox.objects.filter( + intake = Intake.objects.filter( workspace__slug=slug, project_id=project_id, pk=pk ).first() - # Handle default inbox delete - if inbox.is_default: + # Handle default intake delete + if intake.is_default: return Response( - {"error": "You cannot delete the default inbox"}, + {"error": "You cannot delete the default intake"}, status=status.HTTP_400_BAD_REQUEST, ) - inbox.delete() + intake.delete() return Response(status=status.HTTP_204_NO_CONTENT) -class InboxIssueViewSet(BaseViewSet): +class IntakeIssueViewSet(BaseViewSet): - serializer_class = InboxIssueSerializer - model = InboxIssue + serializer_class = IntakeIssueSerializer + model = IntakeIssue filterset_fields = [ - "status", + "statulls", ] def get_queryset(self): @@ -107,8 +107,8 @@ def get_queryset(self): .prefetch_related("assignees", "labels", "issue_module__module") .prefetch_related( Prefetch( - "issue_inbox", - queryset=InboxIssue.objects.only( + "issue_intake", + queryset=IntakeIssue.objects.only( "status", "duplicate_to", "snoozed_till", "source" ), ) @@ -184,14 +184,14 @@ def get_queryset(self): @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) def list(self, request, slug, project_id): - inbox_id = Inbox.objects.filter( + intake_id = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() project = Project.objects.get(pk=project_id) filters = issue_filters(request.GET, "GET", "issue__") - inbox_issue = ( - InboxIssue.objects.filter( - inbox_id=inbox_id.id, project_id=project_id, **filters + intake_issue = ( + IntakeIssue.objects.filter( + intake_id=intake_id.id, project_id=project_id, **filters ) .select_related("issue") .prefetch_related( @@ -211,14 +211,14 @@ def list(self, request, slug, project_id): ) ) ).order_by(request.GET.get("order_by", "-issue__created_at")) - # inbox status filter - inbox_status = [ + # Intake status filter + intake_status = [ item for item in request.GET.get("status", "-2").split(",") if item != "null" ] - if inbox_status: - inbox_issue = inbox_issue.filter(status__in=inbox_status) + if intake_status: + intake_issue = intake_issue.filter(status__in=intake_status) if ( ProjectMember.objects.filter( @@ -230,12 +230,12 @@ def list(self, request, slug, project_id): ).exists() and not project.guest_view_all_features ): - inbox_issue = inbox_issue.filter(created_by=request.user) + intake_issue = intake_issue.filter(created_by=request.user) return self.paginate( request=request, - queryset=(inbox_issue), - on_results=lambda inbox_issues: InboxIssueSerializer( - inbox_issues, + queryset=(intake_issue), + on_results=lambda intake_issues: IntakeIssueSerializer( + intake_issues, many=True, ).data, ) @@ -261,16 +261,6 @@ def create(self, request, slug, project_id): status=status.HTTP_400_BAD_REQUEST, ) - # Create or get state - state, _ = State.objects.get_or_create( - name="Triage", - group="triage", - description="Default state for managing all Inbox Issues", - project_id=project_id, - color="#ff7700", - is_triage=True, - ) - # create an issue project = Project.objects.get(pk=project_id) serializer = IssueCreateSerializer( @@ -283,15 +273,15 @@ def create(self, request, slug, project_id): ) if serializer.is_valid(): serializer.save() - inbox_id = Inbox.objects.filter( + intake_id = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() - # create an inbox issue - inbox_issue = InboxIssue.objects.create( - inbox_id=inbox_id.id, + # create an intake issue + intake_issue = IntakeIssue.objects.create( + intake_id=intake_id.id, project_id=project_id, issue_id=serializer.data["id"], - source=request.data.get("source", "in-app"), + source=request.data.get("source", "IN-APP"), ) # Create an Issue Activity issue_activity.delay( @@ -304,10 +294,10 @@ def create(self, request, slug, project_id): epoch=int(timezone.now().timestamp()), notification=True, origin=request.META.get("HTTP_ORIGIN"), - inbox=str(inbox_issue.id), + intake=str(intake_issue.id), ) - inbox_issue = ( - InboxIssue.objects.select_related("issue") + intake_issue = ( + IntakeIssue.objects.select_related("issue") .prefetch_related( "issue__labels", "issue__assignees", @@ -339,12 +329,12 @@ def create(self, request, slug, project_id): ), ) .get( - inbox_id=inbox_id.id, + intake_id=intake_id.id, issue_id=serializer.data["id"], project_id=project_id, ) ) - serializer = InboxIssueDetailSerializer(inbox_issue) + serializer = IntakeIssueDetailSerializer(intake_issue) return Response(serializer.data, status=status.HTTP_200_OK) else: return Response( @@ -353,14 +343,14 @@ def create(self, request, slug, project_id): @allow_permission(allowed_roles=[ROLE.ADMIN], creator=True, model=Issue) def partial_update(self, request, slug, project_id, pk): - inbox_id = Inbox.objects.filter( + intake_id = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() - inbox_issue = InboxIssue.objects.get( + intake_issue = IntakeIssue.objects.get( issue_id=pk, workspace__slug=slug, project_id=project_id, - inbox_id=inbox_id, + intake_id=intake_id, ) # Get the project member project_member = ProjectMember.objects.get( @@ -370,11 +360,11 @@ def partial_update(self, request, slug, project_id, pk): is_active=True, ) # Only project members admins and created_by users can access this endpoint - if project_member.role <= 5 and str(inbox_issue.created_by_id) != str( + if project_member.role <= 5 and str(intake_issue.created_by_id) != str( request.user.id ): return Response( - {"error": "You cannot edit inbox issues"}, + {"error": "You cannot edit intake issues"}, status=status.HTTP_400_BAD_REQUEST, ) @@ -405,7 +395,7 @@ def partial_update(self, request, slug, project_id, pk): Value([], output_field=ArrayField(UUIDField())), ), ).get( - pk=inbox_issue.issue_id, + pk=intake_issue.issue_id, workspace__slug=slug, project_id=project_id, ) @@ -443,7 +433,7 @@ def partial_update(self, request, slug, project_id, pk): epoch=int(timezone.now().timestamp()), notification=True, origin=request.META.get("HTTP_ORIGIN"), - inbox=str(inbox_issue.id), + intake=str(intake_issue.id), ) issue_serializer.save() else: @@ -451,20 +441,20 @@ def partial_update(self, request, slug, project_id, pk): issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST ) - # Only project admins and members can edit inbox issue attributes + # Only project admins and members can edit intake issue attributes if project_member.role > 15: - serializer = InboxIssueSerializer( - inbox_issue, data=request.data, partial=True + serializer = IntakeIssueSerializer( + intake_issue, data=request.data, partial=True ) current_instance = json.dumps( - InboxIssueSerializer(inbox_issue).data, cls=DjangoJSONEncoder + IntakeIssueSerializer(intake_issue).data, cls=DjangoJSONEncoder ) if serializer.is_valid(): serializer.save() # Update the issue state if the issue is rejected or marked as duplicate if serializer.data["status"] in [-1, 2]: issue = Issue.objects.get( - pk=inbox_issue.issue_id, + pk=intake_issue.issue_id, workspace__slug=slug, project_id=project_id, ) @@ -480,7 +470,7 @@ def partial_update(self, request, slug, project_id, pk): # Update the issue state if it is accepted if serializer.data["status"] in [1]: issue = Issue.objects.get( - pk=inbox_issue.issue_id, + pk=intake_issue.issue_id, workspace__slug=slug, project_id=project_id, ) @@ -498,7 +488,7 @@ def partial_update(self, request, slug, project_id, pk): issue.save() # create a activity for status change issue_activity.delay( - type="inbox.activity.created", + type="intake.activity.created", requested_data=json.dumps( request.data, cls=DjangoJSONEncoder ), @@ -509,11 +499,11 @@ def partial_update(self, request, slug, project_id, pk): epoch=int(timezone.now().timestamp()), notification=False, origin=request.META.get("HTTP_ORIGIN"), - inbox=(inbox_issue.id), + intake=(intake_issue.id), ) - inbox_issue = ( - InboxIssue.objects.select_related("issue") + intake_issue = ( + IntakeIssue.objects.select_related("issue") .prefetch_related( "issue__labels", "issue__assignees", @@ -547,18 +537,18 @@ def partial_update(self, request, slug, project_id, pk): ), ) .get( - inbox_id=inbox_id.id, + intake_id=intake_id.id, issue_id=pk, project_id=project_id, ) ) - serializer = InboxIssueDetailSerializer(inbox_issue).data + serializer = IntakeIssueDetailSerializer(intake_issue).data return Response(serializer, status=status.HTTP_200_OK) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) else: - serializer = InboxIssueDetailSerializer(inbox_issue).data + serializer = IntakeIssueDetailSerializer(intake_issue).data return Response(serializer, status=status.HTTP_200_OK) @allow_permission( @@ -571,12 +561,12 @@ def partial_update(self, request, slug, project_id, pk): model=Issue, ) def retrieve(self, request, slug, project_id, pk): - inbox_id = Inbox.objects.filter( + intake_id = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() project = Project.objects.get(pk=project_id) - inbox_issue = ( - InboxIssue.objects.select_related("issue") + intake_issue = ( + IntakeIssue.objects.select_related("issue") .prefetch_related( "issue__labels", "issue__assignees", @@ -605,7 +595,7 @@ def retrieve(self, request, slug, project_id, pk): Value([], output_field=ArrayField(UUIDField())), ), ) - .get(inbox_id=inbox_id.id, issue_id=pk, project_id=project_id) + .get(intake_id=intake_id.id, issue_id=pk, project_id=project_id) ) if ( ProjectMember.objects.filter( @@ -616,13 +606,13 @@ def retrieve(self, request, slug, project_id, pk): is_active=True, ).exists() and not project.guest_view_all_features - and not inbox_issue.created_by == request.user + and not intake_issue.created_by == request.user ): return Response( {"error": "You are not allowed to view this issue"}, status=status.HTTP_400_BAD_REQUEST, ) - issue = InboxIssueDetailSerializer(inbox_issue).data + issue = IntakeIssueDetailSerializer(intake_issue).data return Response( issue, status=status.HTTP_200_OK, @@ -630,23 +620,23 @@ def retrieve(self, request, slug, project_id, pk): @allow_permission(allowed_roles=[ROLE.ADMIN], creator=True, model=Issue) def destroy(self, request, slug, project_id, pk): - inbox_id = Inbox.objects.filter( + intake_id = Intake.objects.filter( workspace__slug=slug, project_id=project_id ).first() - inbox_issue = InboxIssue.objects.get( + intake_issue = IntakeIssue.objects.get( issue_id=pk, workspace__slug=slug, project_id=project_id, - inbox_id=inbox_id, + intake_id=intake_id, ) # Check the issue status - if inbox_issue.status in [-2, -1, 0, 2]: + if intake_issue.status in [-2, -1, 0, 2]: # Delete the issue also issue = Issue.objects.filter( workspace__slug=slug, project_id=project_id, pk=pk ).first() issue.delete() - inbox_issue.delete() + intake_issue.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/apiserver/plane/app/views/issue/archive.py b/apiserver/plane/app/views/issue/archive.py index 2c6781e59e7..292d9d61734 100644 --- a/apiserver/plane/app/views/issue/archive.py +++ b/apiserver/plane/app/views/issue/archive.py @@ -171,10 +171,10 @@ def list(self, request, slug, project_id): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -200,10 +200,10 @@ def list(self, request, slug, project_id): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/app/views/issue/base.py b/apiserver/plane/app/views/issue/base.py index d82ae432e9e..c30f889ba01 100644 --- a/apiserver/plane/app/views/issue/base.py +++ b/apiserver/plane/app/views/issue/base.py @@ -336,10 +336,10 @@ def list(self, request, slug, project_id): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -364,10 +364,10 @@ def list(self, request, slug, project_id): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/app/views/module/issue.py b/apiserver/plane/app/views/module/issue.py index 565196b3689..dd829753cbf 100644 --- a/apiserver/plane/app/views/module/issue.py +++ b/apiserver/plane/app/views/module/issue.py @@ -160,10 +160,10 @@ def list(self, request, slug, project_id, module_id): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -189,10 +189,10 @@ def list(self, request, slug, project_id, module_id): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/app/views/notification/base.py b/apiserver/plane/app/views/notification/base.py index b8e34339ce5..c4aa1496904 100644 --- a/apiserver/plane/app/views/notification/base.py +++ b/apiserver/plane/app/views/notification/base.py @@ -53,9 +53,9 @@ def list(self, request, slug): mentioned = request.GET.get("mentioned", False) q_filters = Q() - inbox_issue = Issue.objects.filter( + intake_issue = Issue.objects.filter( pk=OuterRef("entity_identifier"), - issue_inbox__status__in=[0, 2, -2], + issue_intake__status__in=[0, 2, -2], workspace__slug=self.kwargs.get("slug"), ) @@ -64,7 +64,8 @@ def list(self, request, slug): workspace__slug=slug, receiver_id=request.user.id ) .filter(entity_name="issue") - .annotate(is_inbox_issue=Exists(inbox_issue)) + .annotate(is_inbox_issue=Exists(intake_issue)) + .annotate(is_intake_issue=Exists(intake_issue)) .annotate( is_mentioned_notification=Case( When(sender__icontains="mentioned", then=True), diff --git a/apiserver/plane/app/views/project/base.py b/apiserver/plane/app/views/project/base.py index 4afc747c35b..faba6c56b36 100644 --- a/apiserver/plane/app/views/project/base.py +++ b/apiserver/plane/app/views/project/base.py @@ -38,7 +38,7 @@ from plane.db.models import ( UserFavorite, Cycle, - Inbox, + Intake, DeployBoard, IssueUserProperty, Issue, @@ -449,14 +449,14 @@ def partial_update(self, request, slug, pk=None): if serializer.is_valid(): serializer.save() - if serializer.data["inbox_view"]: - inbox = Inbox.objects.filter( + if serializer.data["intake_view"] or request.data.get("inbox_view", False): + intake = Intake.objects.filter( project=project, is_default=True, ).first() - if not inbox: - Inbox.objects.create( - name=f"{project.name} Inbox", + if not intake: + Intake.objects.create( + name=f"{project.name} Intake", project=project, is_default=True, ) @@ -465,7 +465,7 @@ def partial_update(self, request, slug, pk=None): State.objects.get_or_create( name="Triage", group="triage", - description="Default state for managing all Inbox Issues", + description="Default state for managing all Intake Issues", project_id=pk, color="#ff7700", is_triage=True, @@ -759,7 +759,7 @@ def list(self, request, slug, project_id): def create(self, request, slug, project_id): comments = request.data.get("is_comments_enabled", False) reactions = request.data.get("is_reactions_enabled", False) - inbox = request.data.get("inbox", None) + intake = request.data.get("intake", None) votes = request.data.get("is_votes_enabled", False) views = request.data.get( "views", @@ -777,7 +777,7 @@ def create(self, request, slug, project_id): entity_identifier=project_id, project_id=project_id, ) - project_deploy_board.inbox = inbox + project_deploy_board.intake = intake project_deploy_board.view_props = views project_deploy_board.is_votes_enabled = votes project_deploy_board.is_comments_enabled = comments diff --git a/apiserver/plane/app/views/view/base.py b/apiserver/plane/app/views/view/base.py index e999dc32926..53c962e7023 100644 --- a/apiserver/plane/app/views/view/base.py +++ b/apiserver/plane/app/views/view/base.py @@ -370,10 +370,10 @@ def list(self, request, slug): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -399,10 +399,10 @@ def list(self, request, slug): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/app/views/workspace/user.py b/apiserver/plane/app/views/workspace/user.py index 6e54e8e455b..fe7b72cd165 100644 --- a/apiserver/plane/app/views/workspace/user.py +++ b/apiserver/plane/app/views/workspace/user.py @@ -204,10 +204,10 @@ def get(self, request, slug, user_id): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), @@ -231,10 +231,10 @@ def get(self, request, slug, user_id): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/bgtasks/dummy_data_task.py b/apiserver/plane/bgtasks/dummy_data_task.py index 21ca32afb37..88928621953 100644 --- a/apiserver/plane/bgtasks/dummy_data_task.py +++ b/apiserver/plane/bgtasks/dummy_data_task.py @@ -30,8 +30,8 @@ Page, ProjectPage, PageLabel, - Inbox, - InboxIssue, + Intake, + IntakeIssue, ) @@ -47,7 +47,7 @@ def create_project(workspace, user_id): : random.randint(2, 12 if len(name) - 1 >= 12 else len(name) - 1) ].upper(), created_by_id=user_id, - inbox_view=True, + intake_view=True, ) # Add current member as project member @@ -406,18 +406,18 @@ def create_issues(workspace, project, user_id, issue_count): return issues -def create_inbox_issues(workspace, project, user_id, inbox_issue_count): - issues = create_issues(workspace, project, user_id, inbox_issue_count) - inbox, create = Inbox.objects.get_or_create( - name="Inbox", +def create_intake_issues(workspace, project, user_id, intake_issue_count): + issues = create_issues(workspace, project, user_id, intake_issue_count) + intake, create = Intake.objects.get_or_create( + name="Intake", project=project, is_default=True, ) - InboxIssue.objects.bulk_create( + IntakeIssue.objects.bulk_create( [ - InboxIssue( + IntakeIssue( issue=issue, - inbox=inbox, + intake=intake, status=(status := [-2, -1, 0, 1, 2][random.randint(0, 4)]), snoozed_till=( datetime.now() + timedelta(days=random.randint(1, 30)) @@ -599,7 +599,7 @@ def create_dummy_data( cycle_count, module_count, pages_count, - inbox_issue_count, + intake_issue_count, ): workspace = Workspace.objects.get(slug=slug) @@ -660,12 +660,12 @@ def create_dummy_data( issue_count=issue_count, ) - # create inbox issues - create_inbox_issues( + # create intake issues + create_intake_issues( workspace=workspace, project=project, user_id=user_id, - inbox_issue_count=inbox_issue_count, + intake_issue_count=intake_issue_count, ) # create issue parent diff --git a/apiserver/plane/bgtasks/issue_activities_task.py b/apiserver/plane/bgtasks/issue_activities_task.py index 371204aa8a6..23239dddb8b 100644 --- a/apiserver/plane/bgtasks/issue_activities_task.py +++ b/apiserver/plane/bgtasks/issue_activities_task.py @@ -1567,7 +1567,7 @@ def delete_draft_issue_activity( ) -def create_inbox_activity( +def create_intake_activity( requested_data, current_instance, issue_id, @@ -1596,8 +1596,8 @@ def create_inbox_activity( issue_id=issue_id, project_id=project_id, workspace_id=workspace_id, - comment="updated the inbox status", - field="inbox", + comment="updated the intake status", + field="intake", verb=requested_data.get("status"), actor_id=actor_id, epoch=epoch, @@ -1620,7 +1620,7 @@ def issue_activity( subscriber=True, notification=False, origin=None, - inbox=None, + intake=None, ): try: issue_activities = [] @@ -1668,7 +1668,7 @@ def issue_activity( "issue_draft.activity.created": create_draft_issue_activity, "issue_draft.activity.updated": update_draft_issue_activity, "issue_draft.activity.deleted": delete_draft_issue_activity, - "inbox.activity.created": create_inbox_activity, + "intake.activity.created": create_intake_activity, } func = ACTIVITY_MAPPER.get(type) @@ -1695,12 +1695,12 @@ def issue_activity( event=( "issue_comment" if activity.field == "comment" - else "inbox_issue" if inbox else "issue" + else "intake_issue" if intake else "issue" ), event_id=( activity.issue_comment_id if activity.field == "comment" - else inbox if inbox else activity.issue_id + else intake if intake else activity.issue_id ), verb=activity.verb, field=( diff --git a/apiserver/plane/bgtasks/issue_automation_task.py b/apiserver/plane/bgtasks/issue_automation_task.py index e7ca16a984b..7e50106a03f 100644 --- a/apiserver/plane/bgtasks/issue_automation_task.py +++ b/apiserver/plane/bgtasks/issue_automation_task.py @@ -51,10 +51,10 @@ def archive_old_issues(): & Q(issue_module__isnull=False) ), ).filter( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True) + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True) ) # Check if Issues @@ -129,10 +129,10 @@ def close_old_issues(): & Q(issue_module__isnull=False) ), ).filter( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True) + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__isnull=True) ) # Check if Issues diff --git a/apiserver/plane/bgtasks/webhook_task.py b/apiserver/plane/bgtasks/webhook_task.py index 7614c4b2f57..4670b084d19 100644 --- a/apiserver/plane/bgtasks/webhook_task.py +++ b/apiserver/plane/bgtasks/webhook_task.py @@ -27,7 +27,7 @@ ModuleSerializer, ProjectSerializer, UserLiteSerializer, - InboxIssueSerializer, + IntakeIssueSerializer, ) from plane.db.models import ( Cycle, @@ -40,7 +40,7 @@ User, Webhook, WebhookLog, - InboxIssue, + IntakeIssue, ) from plane.license.utils.instance_value import get_email_configuration from plane.utils.exception_logger import log_exception @@ -54,7 +54,7 @@ "module_issue": ModuleIssueSerializer, "issue_comment": IssueCommentSerializer, "user": UserLiteSerializer, - "inbox_issue": InboxIssueSerializer, + "intake_issue": IntakeIssueSerializer, } MODEL_MAPPER = { @@ -66,7 +66,7 @@ "module_issue": ModuleIssue, "issue_comment": IssueComment, "user": User, - "inbox_issue": InboxIssue, + "intake_issue": IntakeIssue, } diff --git a/apiserver/plane/db/management/commands/create_dummy_data.py b/apiserver/plane/db/management/commands/create_dummy_data.py index f71d90f0eee..64637864d1a 100644 --- a/apiserver/plane/db/management/commands/create_dummy_data.py +++ b/apiserver/plane/db/management/commands/create_dummy_data.py @@ -62,13 +62,15 @@ def handle(self, *args: Any, **options: Any) -> str | None: project_count = int(input("Number of projects to be created: ")) for i in range(project_count): - print(f"Please provide the following details for project {i+1}:") + print( + f"Please provide the following details for project {i+1}:" + ) issue_count = int(input("Number of issues to be created: ")) cycle_count = int(input("Number of cycles to be created: ")) module_count = int(input("Number of modules to be created: ")) pages_count = int(input("Number of pages to be created: ")) - inbox_issue_count = int( - input("Number of inbox issues to be created: ") + intake_issue_count = int( + input("Number of intake issues to be created: ") ) from plane.bgtasks.dummy_data_task import create_dummy_data @@ -81,7 +83,7 @@ def handle(self, *args: Any, **options: Any) -> str | None: cycle_count=cycle_count, module_count=module_count, pages_count=pages_count, - inbox_issue_count=inbox_issue_count, + intake_issue_count=intake_issue_count, ) self.stdout.write( diff --git a/apiserver/plane/db/migrations/0085_intake_intakeissue_remove_inboxissue_created_by_and_more.py b/apiserver/plane/db/migrations/0085_intake_intakeissue_remove_inboxissue_created_by_and_more.py new file mode 100644 index 00000000000..36cf73bc541 --- /dev/null +++ b/apiserver/plane/db/migrations/0085_intake_intakeissue_remove_inboxissue_created_by_and_more.py @@ -0,0 +1,141 @@ +# Generated by Django 4.2.15 on 2024-11-06 08:41 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more'), + ] + + operations = [ + migrations.RenameModel( + old_name="Inbox", + new_name="Intake", + ), + migrations.AlterModelTable( + name="Intake", + table="intakes", + ), + migrations.AlterModelOptions( + name="Intake", + options={ + "verbose_name": "Intake", + "verbose_name_plural": "Intakes", + "ordering": ("name",), + }, + ), + migrations.AlterField( + model_name="Intake", + name="description", + field=models.TextField( + blank=True, verbose_name="Intake Description" + ), + ), + migrations.RenameModel( + old_name="InboxIssue", + new_name="IntakeIssue", + ), + # Rename the 'inbox' field to 'intake' + migrations.RenameField( + model_name="IntakeIssue", + old_name="inbox", + new_name="intake", + ), + # Update ForeignKey related_name for 'intake' + migrations.AlterField( + model_name="IntakeIssue", + name="intake", + field=models.ForeignKey( + "db.Intake", + related_name="issue_intake", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + # Update ForeignKey related_name for 'issue' + migrations.AlterField( + model_name="IntakeIssue", + name="issue", + field=models.ForeignKey( + "db.Issue", + related_name="issue_intake", + on_delete=django.db.models.deletion.CASCADE, + ), + ), + # Update ForeignKey related_name for 'duplicate_to' + migrations.AlterField( + model_name="IntakeIssue", + name="duplicate_to", + field=models.ForeignKey( + "db.Issue", + related_name="intake_duplicate", + on_delete=django.db.models.deletion.SET_NULL, + null=True, + ), + ), + # Update Meta options + migrations.AlterModelOptions( + name="IntakeIssue", + options={ + "verbose_name": "IntakeIssue", + "verbose_name_plural": "IntakeIssues", + "ordering": ("-created_at",), + }, + ), + # Update db_table + migrations.AlterModelTable( + name="IntakeIssue", + table="intake_issues", + ), + migrations.RenameField( + model_name="project", + old_name="inbox_view", + new_name="intake_view", + ), + migrations.RenameField( + model_name="deployboard", + old_name="inbox", + new_name="intake", + ), + migrations.RenameField( + model_name="projectdeployboard", + old_name="inbox", + new_name="intake", + ), + migrations.RemoveConstraint( + model_name="intake", + name="inbox_unique_name_project_when_deleted_at_null", + ), + migrations.AlterField( + model_name="deployboard", + name="intake", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="publish_intake", + to="db.intake", + ), + ), + migrations.AlterField( + model_name="projectdeployboard", + name="intake", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="board_intake", + to="db.intake", + ), + ), + migrations.AddConstraint( + model_name="intake", + constraint=models.UniqueConstraint( + condition=models.Q(("deleted_at__isnull", True)), + fields=("name", "project"), + name="intake_unique_name_project_when_deleted_at_null", + ), + ), + ] diff --git a/apiserver/plane/db/models/__init__.py b/apiserver/plane/db/models/__init__.py index dd91a4b1d39..ff930447ac9 100644 --- a/apiserver/plane/db/models/__init__.py +++ b/apiserver/plane/db/models/__init__.py @@ -15,7 +15,7 @@ from .estimate import Estimate, EstimatePoint from .exporter import ExporterHistory from .importer import Importer -from .inbox import Inbox, InboxIssue +from .intake import Intake, IntakeIssue from .integration import ( GithubCommentSync, GithubIssueSync, @@ -93,7 +93,7 @@ from .estimate import Estimate, EstimatePoint -from .inbox import Inbox, InboxIssue +from .intake import Intake, IntakeIssue from .analytic import AnalyticView diff --git a/apiserver/plane/db/models/deploy_board.py b/apiserver/plane/db/models/deploy_board.py index 2bffe57962e..f72d1155b9e 100644 --- a/apiserver/plane/db/models/deploy_board.py +++ b/apiserver/plane/db/models/deploy_board.py @@ -34,9 +34,9 @@ class DeployBoard(WorkspaceBaseModel): ) is_comments_enabled = models.BooleanField(default=False) is_reactions_enabled = models.BooleanField(default=False) - inbox = models.ForeignKey( - "db.Inbox", - related_name="board_inbox", + intake = models.ForeignKey( + "db.Intake", + related_name="publish_intake", on_delete=models.SET_NULL, null=True, ) diff --git a/apiserver/plane/db/models/inbox.py b/apiserver/plane/db/models/intake.py similarity index 69% rename from apiserver/plane/db/models/inbox.py rename to apiserver/plane/db/models/intake.py index 95c84be46f4..2a4bf75cabb 100644 --- a/apiserver/plane/db/models/inbox.py +++ b/apiserver/plane/db/models/intake.py @@ -5,17 +5,17 @@ from plane.db.models.project import ProjectBaseModel -class Inbox(ProjectBaseModel): +class Intake(ProjectBaseModel): name = models.CharField(max_length=255) description = models.TextField( - verbose_name="Inbox Description", blank=True + verbose_name="Intake Description", blank=True ) is_default = models.BooleanField(default=False) view_props = models.JSONField(default=dict) logo_props = models.JSONField(default=dict) def __str__(self): - """Return name of the Inbox""" + """Return name of the intake""" return f"{self.name} <{self.project.name}>" class Meta: @@ -24,21 +24,21 @@ class Meta: models.UniqueConstraint( fields=["name", "project"], condition=models.Q(deleted_at__isnull=True), - name="inbox_unique_name_project_when_deleted_at_null", + name="intake_unique_name_project_when_deleted_at_null", ) ] - verbose_name = "Inbox" - verbose_name_plural = "Inboxes" - db_table = "inboxes" + verbose_name = "Intake" + verbose_name_plural = "Intakes" + db_table = "intakes" ordering = ("name",) -class InboxIssue(ProjectBaseModel): - inbox = models.ForeignKey( - "db.Inbox", related_name="issue_inbox", on_delete=models.CASCADE +class IntakeIssue(ProjectBaseModel): + intake = models.ForeignKey( + "db.Intake", related_name="issue_intake", on_delete=models.CASCADE ) issue = models.ForeignKey( - "db.Issue", related_name="issue_inbox", on_delete=models.CASCADE + "db.Issue", related_name="issue_intake", on_delete=models.CASCADE ) status = models.IntegerField( choices=( @@ -53,7 +53,7 @@ class InboxIssue(ProjectBaseModel): snoozed_till = models.DateTimeField(null=True) duplicate_to = models.ForeignKey( "db.Issue", - related_name="inbox_duplicate", + related_name="intake_duplicate", on_delete=models.SET_NULL, null=True, ) @@ -69,11 +69,11 @@ class InboxIssue(ProjectBaseModel): extra = models.JSONField(default=dict) class Meta: - verbose_name = "InboxIssue" - verbose_name_plural = "InboxIssues" - db_table = "inbox_issues" + verbose_name = "IntakeIssue" + verbose_name_plural = "IntakeIssues" + db_table = "intake_issues" ordering = ("-created_at",) def __str__(self): """Return name of the Issue""" - return f"{self.issue.name} <{self.inbox.name}>" + return f"{self.issue.name} <{self.intake.name}>" diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 6360d1fa3aa..adede2982fd 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -86,10 +86,10 @@ def get_queryset(self): super() .get_queryset() .filter( - models.Q(issue_inbox__status=1) - | models.Q(issue_inbox__status=-1) - | models.Q(issue_inbox__status=2) - | models.Q(issue_inbox__isnull=True) + models.Q(issue_intake__status=1) + | models.Q(issue_intake__status=-1) + | models.Q(issue_intake__status=2) + | models.Q(issue_intake__isnull=True) ) .filter(deleted_at__isnull=True) .filter(state__is_triage=False) diff --git a/apiserver/plane/db/models/project.py b/apiserver/plane/db/models/project.py index 55c45fc2a45..c55ffe64635 100644 --- a/apiserver/plane/db/models/project.py +++ b/apiserver/plane/db/models/project.py @@ -95,7 +95,7 @@ class Project(BaseModel): cycle_view = models.BooleanField(default=True) issue_views_view = models.BooleanField(default=True) page_view = models.BooleanField(default=True) - inbox_view = models.BooleanField(default=False) + intake_view = models.BooleanField(default=False) is_time_tracking_enabled = models.BooleanField(default=False) is_issue_type_enabled = models.BooleanField(default=False) guest_view_all_features = models.BooleanField(default=False) @@ -309,9 +309,9 @@ class ProjectDeployBoard(ProjectBaseModel): ) comments = models.BooleanField(default=False) reactions = models.BooleanField(default=False) - inbox = models.ForeignKey( - "db.Inbox", - related_name="bord_inbox", + intake = models.ForeignKey( + "db.Intake", + related_name="board_intake", on_delete=models.SET_NULL, null=True, ) diff --git a/apiserver/plane/space/serializer/inbox.py b/apiserver/plane/space/serializer/intake.py similarity index 81% rename from apiserver/plane/space/serializer/inbox.py rename to apiserver/plane/space/serializer/intake.py index 48ec7c89d72..b1e536b6d34 100644 --- a/apiserver/plane/space/serializer/inbox.py +++ b/apiserver/plane/space/serializer/intake.py @@ -9,16 +9,16 @@ from .issue import IssueFlatSerializer, LabelLiteSerializer from plane.db.models import ( Issue, - InboxIssue, + IntakeIssue, ) -class InboxIssueSerializer(BaseSerializer): +class IntakeIssueSerializer(BaseSerializer): issue_detail = IssueFlatSerializer(source="issue", read_only=True) project_detail = ProjectLiteSerializer(source="project", read_only=True) class Meta: - model = InboxIssue + model = IntakeIssue fields = "__all__" read_only_fields = [ "project", @@ -26,14 +26,14 @@ class Meta: ] -class InboxIssueLiteSerializer(BaseSerializer): +class IntakeIssueLiteSerializer(BaseSerializer): class Meta: - model = InboxIssue + model = IntakeIssue fields = ["id", "status", "duplicate_to", "snoozed_till", "source"] read_only_fields = fields -class IssueStateInboxSerializer(BaseSerializer): +class IssueStateIntakeSerializer(BaseSerializer): state_detail = StateLiteSerializer(read_only=True, source="state") project_detail = ProjectLiteSerializer(read_only=True, source="project") label_details = LabelLiteSerializer( @@ -44,7 +44,7 @@ class IssueStateInboxSerializer(BaseSerializer): ) sub_issues_count = serializers.IntegerField(read_only=True) bridge_id = serializers.UUIDField(read_only=True) - issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True) + issue_intake = IntakeIssueLiteSerializer(read_only=True, many=True) class Meta: model = Issue diff --git a/apiserver/plane/space/urls/__init__.py b/apiserver/plane/space/urls/__init__.py index 418665a0bd4..3ef68006e22 100644 --- a/apiserver/plane/space/urls/__init__.py +++ b/apiserver/plane/space/urls/__init__.py @@ -1,11 +1,11 @@ -from .inbox import urlpatterns as inbox_urls +from .intake import urlpatterns as intake_urls from .issue import urlpatterns as issue_urls from .project import urlpatterns as project_urls from .asset import urlpatterns as asset_urls urlpatterns = [ - *inbox_urls, + *intake_urls, *issue_urls, *project_urls, *asset_urls, diff --git a/apiserver/plane/space/urls/inbox.py b/apiserver/plane/space/urls/intake.py similarity index 50% rename from apiserver/plane/space/urls/inbox.py rename to apiserver/plane/space/urls/intake.py index 4113235c2e7..9f43a28098b 100644 --- a/apiserver/plane/space/urls/inbox.py +++ b/apiserver/plane/space/urls/intake.py @@ -2,15 +2,26 @@ from plane.space.views import ( - InboxIssuePublicViewSet, + IntakeIssuePublicViewSet, + IssueVotePublicViewSet, WorkspaceProjectDeployBoardEndpoint, ) urlpatterns = [ path( - "anchor//inboxes//inbox-issues/", - InboxIssuePublicViewSet.as_view( + "anchor//intakes//intake-issues/", + IntakeIssuePublicViewSet.as_view( + { + "get": "list", + "post": "create", + } + ), + name="intake-issue", + ), + path( + "anchor//intakes//inbox-issues/", + IntakeIssuePublicViewSet.as_view( { "get": "list", "post": "create", @@ -19,15 +30,15 @@ name="inbox-issue", ), path( - "anchor//inboxes//inbox-issues//", - InboxIssuePublicViewSet.as_view( + "anchor//intakes//intake-issues//", + IntakeIssuePublicViewSet.as_view( { "get": "retrieve", "patch": "partial_update", "delete": "destroy", } ), - name="inbox-issue", + name="intake-issue", ), path( "workspaces//project-boards/", diff --git a/apiserver/plane/space/views/__init__.py b/apiserver/plane/space/views/__init__.py index 4210c1ec114..4167bdaf825 100644 --- a/apiserver/plane/space/views/__init__.py +++ b/apiserver/plane/space/views/__init__.py @@ -14,7 +14,7 @@ ProjectIssuesPublicEndpoint, ) -from .inbox import InboxIssuePublicViewSet +from .intake import IntakeIssuePublicViewSet from .cycle import ProjectCyclesEndpoint diff --git a/apiserver/plane/space/views/inbox.py b/apiserver/plane/space/views/intake.py similarity index 77% rename from apiserver/plane/space/views/inbox.py rename to apiserver/plane/space/views/intake.py index a538a34caae..d9b12b0223f 100644 --- a/apiserver/plane/space/views/inbox.py +++ b/apiserver/plane/space/views/intake.py @@ -13,7 +13,7 @@ # Module imports from .base import BaseViewSet from plane.db.models import ( - InboxIssue, + IntakeIssue, Issue, State, IssueLink, @@ -22,17 +22,17 @@ ) from plane.app.serializers import ( IssueSerializer, - InboxIssueSerializer, + IntakeIssueSerializer, IssueCreateSerializer, - IssueStateInboxSerializer, + IssueStateIntakeSerializer, ) from plane.utils.issue_filters import issue_filters from plane.bgtasks.issue_activities_task import issue_activity -class InboxIssuePublicViewSet(BaseViewSet): - serializer_class = InboxIssueSerializer - model = InboxIssue +class IntakeIssuePublicViewSet(BaseViewSet): + serializer_class = IntakeIssueSerializer + model = IntakeIssue filterset_fields = [ "status", @@ -52,34 +52,34 @@ def get_queryset(self): | Q(snoozed_till__isnull=True), project_id=self.kwargs.get("project_id"), workspace__slug=self.kwargs.get("slug"), - inbox_id=self.kwargs.get("inbox_id"), + intake_id=self.kwargs.get("intake_id"), ) .select_related("issue", "workspace", "project") ) - return InboxIssue.objects.none() + return IntakeIssue.objects.none() - def list(self, request, anchor, inbox_id): + def list(self, request, anchor, intake_id): project_deploy_board = DeployBoard.objects.get( anchor=anchor, entity_name="project" ) - if project_deploy_board.inbox is None: + if project_deploy_board.intake is None: return Response( - {"error": "Inbox is not enabled for this Project Board"}, + {"error": "Intake is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST, ) filters = issue_filters(request.query_params, "GET") issues = ( Issue.objects.filter( - issue_inbox__inbox_id=inbox_id, + issue_intake__intake_id=intake_id, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, ) .filter(**filters) - .annotate(bridge_id=F("issue_inbox__id")) + .annotate(bridge_id=F("issue_intake__id")) .select_related("workspace", "project", "state", "parent") .prefetch_related("assignees", "labels") - .order_by("issue_inbox__snoozed_till", "issue_inbox__status") + .order_by("issue_intake__snoozed_till", "issue_intake__status") .annotate( sub_issues_count=Issue.issue_objects.filter( parent=OuterRef("id") @@ -105,26 +105,26 @@ def list(self, request, anchor, inbox_id): ) .prefetch_related( Prefetch( - "issue_inbox", - queryset=InboxIssue.objects.only( + "issue_intake", + queryset=IntakeIssue.objects.only( "status", "duplicate_to", "snoozed_till", "source" ), ) ) ) - issues_data = IssueStateInboxSerializer(issues, many=True).data + issues_data = IssueStateIntakeSerializer(issues, many=True).data return Response( issues_data, status=status.HTTP_200_OK, ) - def create(self, request, anchor, inbox_id): + def create(self, request, anchor, intake_id): project_deploy_board = DeployBoard.objects.get( anchor=anchor, entity_name="project" ) - if project_deploy_board.inbox is None: + if project_deploy_board.intake is None: return Response( - {"error": "Inbox is not enabled for this Project Board"}, + {"error": "Intake is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST, ) @@ -151,7 +151,7 @@ def create(self, request, anchor, inbox_id): state, _ = State.objects.get_or_create( name="Triage", group="backlog", - description="Default state for managing all Inbox Issues", + description="Default state for managing all Intake Issues", project_id=project_deploy_board.project_id, color="#ff7700", ) @@ -178,37 +178,37 @@ def create(self, request, anchor, inbox_id): current_instance=None, epoch=int(timezone.now().timestamp()), ) - # create an inbox issue - InboxIssue.objects.create( - inbox_id=inbox_id, + # create an intake issue + IntakeIssue.objects.create( + intake_id=intake_id, project_id=project_deploy_board.project_id, issue=issue, - source=request.data.get("source", "in-app"), + source=request.data.get("source", "IN-APP"), ) - serializer = IssueStateInboxSerializer(issue) + serializer = IssueStateIntakeSerializer(issue) return Response(serializer.data, status=status.HTTP_200_OK) - def partial_update(self, request, anchor, inbox_id, pk): + def partial_update(self, request, anchor, intake_id, pk): project_deploy_board = DeployBoard.objects.get( anchor=anchor, entity_name="project" ) - if project_deploy_board.inbox is None: + if project_deploy_board.intake is None: return Response( - {"error": "Inbox is not enabled for this Project Board"}, + {"error": "Intake is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST, ) - inbox_issue = InboxIssue.objects.get( + intake_issue = IntakeIssue.objects.get( pk=pk, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, - inbox_id=inbox_id, + intake_id=intake_id, ) # Get the project member - if str(inbox_issue.created_by_id) != str(request.user.id): + if str(intake_issue.created_by_id) != str(request.user.id): return Response( - {"error": "You cannot edit inbox issues"}, + {"error": "You cannot edit intake issues"}, status=status.HTTP_400_BAD_REQUEST, ) @@ -216,7 +216,7 @@ def partial_update(self, request, anchor, inbox_id, pk): issue_data = request.data.pop("issue", False) issue = Issue.objects.get( - pk=inbox_issue.issue_id, + pk=intake_issue.issue_id, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, ) @@ -256,52 +256,52 @@ def partial_update(self, request, anchor, inbox_id, pk): issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST ) - def retrieve(self, request, anchor, inbox_id, pk): + def retrieve(self, request, anchor, intake_id, pk): project_deploy_board = DeployBoard.objects.get( anchor=anchor, entity_name="project" ) - if project_deploy_board.inbox is None: + if project_deploy_board.intake is None: return Response( - {"error": "Inbox is not enabled for this Project Board"}, + {"error": "Intake is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST, ) - inbox_issue = InboxIssue.objects.get( + intake_issue = IntakeIssue.objects.get( pk=pk, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, - inbox_id=inbox_id, + intake_id=intake_id, ) issue = Issue.objects.get( - pk=inbox_issue.issue_id, + pk=intake_issue.issue_id, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, ) - serializer = IssueStateInboxSerializer(issue) + serializer = IssueStateIntakeSerializer(issue) return Response(serializer.data, status=status.HTTP_200_OK) - def destroy(self, request, anchor, inbox_id, pk): + def destroy(self, request, anchor, intake_id, pk): project_deploy_board = DeployBoard.objects.get( anchor=anchor, entity_name="project" ) - if project_deploy_board.inbox is None: + if project_deploy_board.intake is None: return Response( - {"error": "Inbox is not enabled for this Project Board"}, + {"error": "Intake is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST, ) - inbox_issue = InboxIssue.objects.get( + intake_issue = IntakeIssue.objects.get( pk=pk, workspace_id=project_deploy_board.workspace_id, project_id=project_deploy_board.project_id, - inbox_id=inbox_id, + intake_id=intake_id, ) - if str(inbox_issue.created_by_id) != str(request.user.id): + if str(intake_issue.created_by_id) != str(request.user.id): return Response( - {"error": "You cannot delete inbox issue"}, + {"error": "You cannot delete intake issue"}, status=status.HTTP_400_BAD_REQUEST, ) - inbox_issue.delete() + intake_issue.delete() return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/apiserver/plane/space/views/issue.py b/apiserver/plane/space/views/issue.py index 04a3dc4792e..f67b8ebf7c7 100644 --- a/apiserver/plane/space/views/issue.py +++ b/apiserver/plane/space/views/issue.py @@ -194,10 +194,10 @@ def get(self, request, anchor): group_by_field_name=group_by, sub_group_by_field_name=sub_group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__status=True), archived_at__isnull=True, is_draft=False, ), @@ -222,10 +222,10 @@ def get(self, request, anchor): ), group_by_field_name=group_by, count_filter=Q( - Q(issue_inbox__status=1) - | Q(issue_inbox__status=-1) - | Q(issue_inbox__status=2) - | Q(issue_inbox__isnull=True), + Q(issue_intake__status=1) + | Q(issue_intake__status=-1) + | Q(issue_intake__status=2) + | Q(issue_intake__status=True), archived_at__isnull=True, is_draft=False, ), diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index b82ba1e8c75..8cff40a4e0b 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -451,6 +451,27 @@ def filter_module(params, issue_filter, method, prefix=""): return issue_filter +def filter_intake_status(params, issue_filter, method, prefix=""): + if method == "GET": + status = [ + item + for item in params.get("intake_status").split(",") + if item != "null" + ] + if len(status) and "" not in status: + issue_filter[f"{prefix}issue_intake__status__in"] = status + else: + if ( + params.get("intake_status", None) + and len(params.get("intake_status")) + and params.get("intake_status") != "null" + ): + issue_filter[f"{prefix}issue_intake__status__in"] = params.get( + "inbox_status" + ) + return issue_filter + + def filter_inbox_status(params, issue_filter, method, prefix=""): if method == "GET": status = [ @@ -459,14 +480,14 @@ def filter_inbox_status(params, issue_filter, method, prefix=""): if item != "null" ] if len(status) and "" not in status: - issue_filter[f"{prefix}issue_inbox__status__in"] = status + issue_filter[f"{prefix}issue_intake__status__in"] = status else: if ( params.get("inbox_status", None) and len(params.get("inbox_status")) and params.get("inbox_status") != "null" ): - issue_filter[f"{prefix}issue_inbox__status__in"] = params.get( + issue_filter[f"{prefix}issue_intake__status__in"] = params.get( "inbox_status" ) return issue_filter @@ -562,6 +583,7 @@ def issue_filters(query_params, method, prefix=""): "project": filter_project, "cycle": filter_cycle, "module": filter_module, + "intake_status": filter_intake_status, "inbox_status": filter_inbox_status, "sub_issue": filter_sub_issue_toggle, "subscriber": filter_subscribed_issues,