From c009a45887525cc3e445339b2164ee69b69fa4f3 Mon Sep 17 00:00:00 2001 From: NarayanBavisetti Date: Wed, 8 May 2024 13:47:40 +0530 Subject: [PATCH 1/2] chore: pages realtime --- apiserver/plane/app/serializers/page.py | 6 ++++- apiserver/plane/app/urls/page.py | 11 ++++++++ apiserver/plane/app/views/__init__.py | 1 + apiserver/plane/app/views/page/base.py | 36 +++++++++++++++++++++++++ apiserver/plane/db/models/page.py | 1 + 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/apiserver/plane/app/serializers/page.py b/apiserver/plane/app/serializers/page.py index 604ac2c2e..73680cdfd 100644 --- a/apiserver/plane/app/serializers/page.py +++ b/apiserver/plane/app/serializers/page.py @@ -105,9 +105,13 @@ class PageSerializer(BaseSerializer): class PageDetailSerializer(PageSerializer): description_html = serializers.CharField() + description_yjs = serializers.CharField() class Meta(PageSerializer.Meta): - fields = PageSerializer.Meta.fields + ["description_html"] + fields = PageSerializer.Meta.fields + [ + "description_html", + "description_yjs", + ] class SubPageSerializer(BaseSerializer): diff --git a/apiserver/plane/app/urls/page.py b/apiserver/plane/app/urls/page.py index 1a73e4ed3..a6d43600f 100644 --- a/apiserver/plane/app/urls/page.py +++ b/apiserver/plane/app/urls/page.py @@ -6,6 +6,7 @@ from plane.app.views import ( PageFavoriteViewSet, PageLogEndpoint, SubPagesEndpoint, + PagesDescriptionViewSet, ) @@ -79,4 +80,14 @@ urlpatterns = [ SubPagesEndpoint.as_view(), name="sub-page", ), + path( + "workspaces//projects//pages//description/", + PagesDescriptionViewSet.as_view( + { + "get": "retrieve", + "patch": "partial_update", + } + ), + name="page-description", + ), ] diff --git a/apiserver/plane/app/views/__init__.py b/apiserver/plane/app/views/__init__.py index bb61aad3a..dd0ca721b 100644 --- a/apiserver/plane/app/views/__init__.py +++ b/apiserver/plane/app/views/__init__.py @@ -191,6 +191,7 @@ from .page.base import ( PageFavoriteViewSet, PageLogEndpoint, SubPagesEndpoint, + PagesDescriptionViewSet, ) from .search import GlobalSearchEndpoint, IssueSearchEndpoint diff --git a/apiserver/plane/app/views/page/base.py b/apiserver/plane/app/views/page/base.py index 29dc2dbf5..146ad273a 100644 --- a/apiserver/plane/app/views/page/base.py +++ b/apiserver/plane/app/views/page/base.py @@ -1,5 +1,6 @@ # Python imports import json +import base64 from datetime import datetime from django.core.serializers.json import DjangoJSONEncoder @@ -8,6 +9,7 @@ from django.db import connection from django.db.models import Exists, OuterRef, Q from django.utils.decorators import method_decorator from django.views.decorators.gzip import gzip_page +from django.http import StreamingHttpResponse, HttpResponse # Third party imports from rest_framework import status @@ -387,3 +389,37 @@ class SubPagesEndpoint(BaseAPIView): return Response( SubPageSerializer(pages, many=True).data, status=status.HTTP_200_OK ) + + +class PagesDescriptionViewSet(BaseViewSet): + + def retrieve(self, request, slug, project_id, pk): + page = Page.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + binary_data = page.description_yjs + + def stream_data(): + yield binary_data + + response = StreamingHttpResponse( + stream_data(), content_type="application/octet-stream" + ) + response["Content-Disposition"] = ( + 'attachment; filename="page_description.bin"' + ) + return response + + def partial_update(self, request, slug, project_id, pk): + page = Page.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + base64_data = request.data.get("description_yjs") + + if base64_data: + binary_data = base64.b64decode(base64_data) + page.description_yjs = binary_data + page.save() + return Response({"message": "Updated successfully"}) + else: + return Response({"error": "No binary data provided"}) diff --git a/apiserver/plane/db/models/page.py b/apiserver/plane/db/models/page.py index da7e050bb..e7def16d0 100644 --- a/apiserver/plane/db/models/page.py +++ b/apiserver/plane/db/models/page.py @@ -16,6 +16,7 @@ def get_view_props(): class Page(ProjectBaseModel): name = models.CharField(max_length=255) description = models.JSONField(default=dict, blank=True) + description_yjs = models.BinaryField(null=True) description_html = models.TextField(blank=True, default="

") description_stripped = models.TextField(blank=True, null=True) owned_by = models.ForeignKey( From 7dada8a7a08f53e577452c6285cc35760c99810b Mon Sep 17 00:00:00 2001 From: NarayanBavisetti Date: Wed, 8 May 2024 15:25:53 +0530 Subject: [PATCH 2/2] chore: empty binary response --- apiserver/plane/app/views/page/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apiserver/plane/app/views/page/base.py b/apiserver/plane/app/views/page/base.py index 146ad273a..b3ba4f622 100644 --- a/apiserver/plane/app/views/page/base.py +++ b/apiserver/plane/app/views/page/base.py @@ -400,7 +400,10 @@ class PagesDescriptionViewSet(BaseViewSet): binary_data = page.description_yjs def stream_data(): - yield binary_data + if binary_data: + yield binary_data + else: + yield b"" response = StreamingHttpResponse( stream_data(), content_type="application/octet-stream"