From fbfa5369373fbe22d846873bb991475303c53950 Mon Sep 17 00:00:00 2001 From: NarayanBavisetti Date: Fri, 14 Jun 2024 13:30:38 +0530 Subject: [PATCH] chore: archive and draft issue description --- apiserver/plane/app/urls/issue.py | 21 ++++++++++ apiserver/plane/app/views/__init__.py | 6 +-- apiserver/plane/app/views/issue/archive.py | 47 ++++++++++++++++++++++ apiserver/plane/app/views/issue/base.py | 4 +- apiserver/plane/app/views/issue/draft.py | 47 ++++++++++++++++++++++ 5 files changed, 119 insertions(+), 6 deletions(-) diff --git a/apiserver/plane/app/urls/issue.py b/apiserver/plane/app/urls/issue.py index 76c63edfb..cc0109b1a 100644 --- a/apiserver/plane/app/urls/issue.py +++ b/apiserver/plane/app/urls/issue.py @@ -20,6 +20,7 @@ from plane.app.views import ( IssueViewSet, LabelViewSet, IssueDescriptionViewSet, + ArchivedIssueDescriptionViewSet, ) urlpatterns = [ @@ -265,6 +266,16 @@ urlpatterns = [ ), name="project-issue-archive-unarchive", ), + path( + "workspaces//projects//archived-issues//description/", + ArchivedIssueDescriptionViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + } + ), + name="archived-issue-description", + ), ## End Issue Archives ## Issue Relation path( @@ -309,4 +320,14 @@ urlpatterns = [ ), name="project-issue-draft", ), + path( + "workspaces//projects//issue-drafts//description/", + IssueDraftViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + } + ), + name="draft-issue-description", + ), ] diff --git a/apiserver/plane/app/views/__init__.py b/apiserver/plane/app/views/__init__.py index f1dfc8864..ee6cd6c27 100644 --- a/apiserver/plane/app/views/__init__.py +++ b/apiserver/plane/app/views/__init__.py @@ -114,9 +114,7 @@ from .issue.activity import ( IssueActivityEndpoint, ) -from .issue.archive import ( - IssueArchiveViewSet, -) +from .issue.archive import IssueArchiveViewSet, ArchivedIssueDescriptionViewSet from .issue.attachment import ( IssueAttachmentEndpoint, @@ -127,7 +125,7 @@ from .issue.comment import ( CommentReactionViewSet, ) -from .issue.draft import IssueDraftViewSet +from .issue.draft import IssueDraftViewSet, DraftIssueDescriptionViewSet from .issue.label import ( LabelViewSet, diff --git a/apiserver/plane/app/views/issue/archive.py b/apiserver/plane/app/views/issue/archive.py index cc3a343d2..5204ece09 100644 --- a/apiserver/plane/app/views/issue/archive.py +++ b/apiserver/plane/app/views/issue/archive.py @@ -1,5 +1,6 @@ # Python imports import json +import base64 # Django imports from django.utils import timezone @@ -18,6 +19,7 @@ from django.db.models import ( UUIDField, ) from django.core.serializers.json import DjangoJSONEncoder +from django.http import StreamingHttpResponse from django.utils.decorators import method_decorator from django.views.decorators.gzip import gzip_page from django.contrib.postgres.aggregates import ArrayAgg @@ -351,3 +353,48 @@ class IssueArchiveViewSet(BaseViewSet): issue.save() return Response(status=status.HTTP_204_NO_CONTENT) + + +class ArchivedIssueDescriptionViewSet(BaseViewSet): + permission_classes = [ + ProjectEntityPermission, + ] + + def retrieve(self, request, slug, project_id, pk): + issue = Issue.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + binary_data = issue.description_binary + + def stream_data(): + if binary_data: + yield binary_data + else: + yield b"" + + response = StreamingHttpResponse( + stream_data(), content_type="application/octet-stream" + ) + response["Content-Disposition"] = ( + 'attachment; filename="issue_description.bin"' + ) + return response + + def partial_update(self, request, slug, project_id, pk): + issue = Issue.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + + base64_data = request.data.get("description_binary") + + if base64_data: + # Decode the base64 data to bytes + new_binary_data = base64.b64decode(base64_data) + + # Store the updated binary data + issue.description_binary = new_binary_data + issue.description_html = request.data.get("description_html") + issue.save() + return Response({"message": "Updated successfully"}) + else: + return Response({"error": "No binary data provided"}) diff --git a/apiserver/plane/app/views/issue/base.py b/apiserver/plane/app/views/issue/base.py index 8a9e2fe42..f3d94fff7 100644 --- a/apiserver/plane/app/views/issue/base.py +++ b/apiserver/plane/app/views/issue/base.py @@ -682,7 +682,7 @@ class IssueDescriptionViewSet(BaseViewSet): ] def retrieve(self, request, slug, project_id, pk): - issue = Issue.objects.get( + issue = Issue.issue_objects.get( pk=pk, workspace__slug=slug, project_id=project_id ) binary_data = issue.description_binary @@ -702,7 +702,7 @@ class IssueDescriptionViewSet(BaseViewSet): return response def partial_update(self, request, slug, project_id, pk): - issue = Issue.objects.get( + issue = Issue.issue_objects.get( pk=pk, workspace__slug=slug, project_id=project_id ) diff --git a/apiserver/plane/app/views/issue/draft.py b/apiserver/plane/app/views/issue/draft.py index 610c3c468..15cabe309 100644 --- a/apiserver/plane/app/views/issue/draft.py +++ b/apiserver/plane/app/views/issue/draft.py @@ -1,8 +1,10 @@ # Python imports import json +import base64 # Django imports from django.contrib.postgres.aggregates import ArrayAgg +from django.http import StreamingHttpResponse from django.contrib.postgres.fields import ArrayField from django.core.serializers.json import DjangoJSONEncoder from django.db.models import ( @@ -366,3 +368,48 @@ class IssueDraftViewSet(BaseViewSet): origin=request.META.get("HTTP_ORIGIN"), ) return Response(status=status.HTTP_204_NO_CONTENT) + + +class DraftIssueDescriptionViewSet(BaseViewSet): + permission_classes = [ + ProjectEntityPermission, + ] + + def retrieve(self, request, slug, project_id, pk): + issue = Issue.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + binary_data = issue.description_binary + + def stream_data(): + if binary_data: + yield binary_data + else: + yield b"" + + response = StreamingHttpResponse( + stream_data(), content_type="application/octet-stream" + ) + response["Content-Disposition"] = ( + 'attachment; filename="issue_description.bin"' + ) + return response + + def partial_update(self, request, slug, project_id, pk): + issue = Issue.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + + base64_data = request.data.get("description_binary") + + if base64_data: + # Decode the base64 data to bytes + new_binary_data = base64.b64decode(base64_data) + + # Store the updated binary data + issue.description_binary = new_binary_data + issue.description_html = request.data.get("description_html") + issue.save() + return Response({"message": "Updated successfully"}) + else: + return Response({"error": "No binary data provided"})